Commit fe36e70f authored by Rakesh Pillai's avatar Rakesh Pillai Committed by Kalle Valo

ath10k: wait for vdev delete response from firmware

When we add an interface immediately after removing
the interface the vdev deletion in firmware might not
have been completed. We need to synchronize the vdev creation
with the firmware.

Wait for vdev delete response from firmware when we
remove an interface.

Tested HW: WCN3990
Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1
Signed-off-by: default avatarRakesh Pillai <pillair@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 011d4111
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -2197,6 +2197,7 @@ static void ath10k_core_restart(struct work_struct *work) ...@@ -2197,6 +2197,7 @@ static void ath10k_core_restart(struct work_struct *work)
complete(&ar->offchan_tx_completed); complete(&ar->offchan_tx_completed);
complete(&ar->install_key_done); complete(&ar->install_key_done);
complete(&ar->vdev_setup_done); complete(&ar->vdev_setup_done);
complete(&ar->vdev_delete_done);
complete(&ar->thermal.wmi_sync); complete(&ar->thermal.wmi_sync);
complete(&ar->bss_survey_done); complete(&ar->bss_survey_done);
wake_up(&ar->htt.empty_tx_wq); wake_up(&ar->htt.empty_tx_wq);
...@@ -3163,6 +3164,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ...@@ -3163,6 +3164,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_completion(&ar->install_key_done); init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done); init_completion(&ar->vdev_setup_done);
init_completion(&ar->vdev_delete_done);
init_completion(&ar->thermal.wmi_sync); init_completion(&ar->thermal.wmi_sync);
init_completion(&ar->bss_survey_done); init_completion(&ar->bss_survey_done);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/ */
#ifndef _CORE_H_ #ifndef _CORE_H_
...@@ -515,6 +515,7 @@ struct ath10k_sta { ...@@ -515,6 +515,7 @@ struct ath10k_sta {
}; };
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
#define ATH10K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ)
enum ath10k_beacon_state { enum ath10k_beacon_state {
ATH10K_BEACON_SCHEDULED = 0, ATH10K_BEACON_SCHEDULED = 0,
...@@ -1072,6 +1073,7 @@ struct ath10k { ...@@ -1072,6 +1073,7 @@ struct ath10k {
int last_wmi_vdev_start_status; int last_wmi_vdev_start_status;
struct completion vdev_setup_done; struct completion vdev_setup_done;
struct completion vdev_delete_done;
struct workqueue_struct *workqueue; struct workqueue_struct *workqueue;
/* Auxiliary workqueue */ /* Auxiliary workqueue */
......
...@@ -1011,6 +1011,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) ...@@ -1011,6 +1011,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
reinit_completion(&ar->vdev_setup_done); reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_start(ar, &arg); ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) { if (ret) {
...@@ -1060,6 +1061,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ...@@ -1060,6 +1061,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
ar->monitor_vdev_id, ret); ar->monitor_vdev_id, ret);
reinit_completion(&ar->vdev_setup_done); reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret) if (ret)
...@@ -1401,6 +1403,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ...@@ -1401,6 +1403,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->vdev_setup_done); reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
if (ret) { if (ret) {
...@@ -1437,6 +1440,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, ...@@ -1437,6 +1440,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->vdev_setup_done); reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
arg.vdev_id = arvif->vdev_id; arg.vdev_id = arvif->vdev_id;
arg.dtim_period = arvif->dtim_period; arg.dtim_period = arvif->dtim_period;
...@@ -5455,6 +5459,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ...@@ -5455,6 +5459,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = (void *)vif->drv_priv; struct ath10k_vif *arvif = (void *)vif->drv_priv;
struct ath10k_peer *peer; struct ath10k_peer *peer;
unsigned long time_left;
int ret; int ret;
int i; int i;
...@@ -5496,6 +5501,15 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ...@@ -5496,6 +5501,15 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) {
time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
ATH10K_VDEV_DELETE_TIMEOUT_HZ);
if (time_left == 0) {
ath10k_warn(ar, "Timeout in receiving vdev delete response\n");
goto out;
}
}
/* Some firmware revisions don't notify host about self-peer removal /* Some firmware revisions don't notify host about self-peer removal
* until after associated vdev is deleted. * until after associated vdev is deleted.
*/ */
...@@ -5546,6 +5560,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ...@@ -5546,6 +5560,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_mac_txq_unref(ar, vif->txq); ath10k_mac_txq_unref(ar, vif->txq);
out:
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/ */
#include "core.h" #include "core.h"
#include "debug.h" #include "debug.h"
...@@ -212,6 +212,13 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, ...@@ -212,6 +212,13 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
return 0; return 0;
} }
static void ath10k_wmi_tlv_event_vdev_delete_resp(struct ath10k *ar,
struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_DELETE_RESP_EVENTID\n");
complete(&ar->vdev_delete_done);
}
static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar, static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -514,6 +521,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -514,6 +521,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_TLV_VDEV_STOPPED_EVENTID: case WMI_TLV_VDEV_STOPPED_EVENTID:
ath10k_wmi_event_vdev_stopped(ar, skb); ath10k_wmi_event_vdev_stopped(ar, skb);
break; break;
case WMI_TLV_VDEV_DELETE_RESP_EVENTID:
ath10k_wmi_tlv_event_vdev_delete_resp(ar, skb);
break;
case WMI_TLV_PEER_STA_KICKOUT_EVENTID: case WMI_TLV_PEER_STA_KICKOUT_EVENTID:
ath10k_wmi_event_peer_sta_kickout(ar, skb); ath10k_wmi_event_peer_sta_kickout(ar, skb);
break; break;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/ */
#ifndef _WMI_TLV_H #ifndef _WMI_TLV_H
#define _WMI_TLV_H #define _WMI_TLV_H
...@@ -301,6 +301,8 @@ enum wmi_tlv_event_id { ...@@ -301,6 +301,8 @@ enum wmi_tlv_event_id {
WMI_TLV_VDEV_STOPPED_EVENTID, WMI_TLV_VDEV_STOPPED_EVENTID,
WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID, WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID, WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID,
WMI_TLV_VDEV_TSF_REPORT_EVENTID,
WMI_TLV_VDEV_DELETE_RESP_EVENTID,
WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER), WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER),
WMI_TLV_PEER_INFO_EVENTID, WMI_TLV_PEER_INFO_EVENTID,
WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID, WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID,
...@@ -1569,6 +1571,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) ...@@ -1569,6 +1571,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
WMI_SERVICE_MGMT_TX_WMI, len); WMI_SERVICE_MGMT_TX_WMI, len);
SVCMAP(WMI_TLV_SERVICE_MESH_11S, SVCMAP(WMI_TLV_SERVICE_MESH_11S,
WMI_SERVICE_MESH_11S, len); WMI_SERVICE_MESH_11S, len);
SVCMAP(WMI_TLV_SERVICE_SYNC_DELETE_CMDS,
WMI_SERVICE_SYNC_DELETE_CMDS, len);
} }
static inline void static inline void
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/ */
#ifndef _WMI_H_ #ifndef _WMI_H_
...@@ -200,6 +200,7 @@ enum wmi_service { ...@@ -200,6 +200,7 @@ enum wmi_service {
WMI_SERVICE_RTT_RESPONDER_ROLE, WMI_SERVICE_RTT_RESPONDER_ROLE,
WMI_SERVICE_PER_PACKET_SW_ENCRYPT, WMI_SERVICE_PER_PACKET_SW_ENCRYPT,
WMI_SERVICE_REPORT_AIRTIME, WMI_SERVICE_REPORT_AIRTIME,
WMI_SERVICE_SYNC_DELETE_CMDS,
/* Remember to add the new value to wmi_service_name()! */ /* Remember to add the new value to wmi_service_name()! */
...@@ -491,6 +492,7 @@ static inline char *wmi_service_name(enum wmi_service service_id) ...@@ -491,6 +492,7 @@ static inline char *wmi_service_name(enum wmi_service service_id)
SVCSTR(WMI_SERVICE_RTT_RESPONDER_ROLE); SVCSTR(WMI_SERVICE_RTT_RESPONDER_ROLE);
SVCSTR(WMI_SERVICE_PER_PACKET_SW_ENCRYPT); SVCSTR(WMI_SERVICE_PER_PACKET_SW_ENCRYPT);
SVCSTR(WMI_SERVICE_REPORT_AIRTIME); SVCSTR(WMI_SERVICE_REPORT_AIRTIME);
SVCSTR(WMI_SERVICE_SYNC_DELETE_CMDS);
case WMI_SERVICE_MAX: case WMI_SERVICE_MAX:
return NULL; return NULL;
......
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