Commit 3cbbdfbe authored by Ritesh Singh's avatar Ritesh Singh Committed by Kalle Valo
Browse files

ath11k: vdev delete synchronization with firmware



When the interface is added immediately after removing the
interface, vdev deletion in firmware might not have been
completed.

Hence, add vdev_delete_resp_event and wait_event_timeout
to synchronize with firmware.

Signed-off-by: default avatarRitesh Singh <ritesi@codeaurora.org>
Signed-off-by: default avatarMaharaja Kennadyrajan <mkenna@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1605514143-17652-2-git-send-email-mkenna@codeaurora.org
parent 526740b4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -810,6 +810,7 @@ static void ath11k_core_restart(struct work_struct *work)
		complete(&ar->peer_assoc_done);
		complete(&ar->install_key_done);
		complete(&ar->vdev_setup_done);
		complete(&ar->vdev_delete_done);
		complete(&ar->bss_survey_done);
		complete(&ar->thermal.wmi_sync);

+2 −0
Original line number Diff line number Diff line
@@ -430,6 +430,7 @@ struct ath11k_per_peer_tx_stats {
};

#define ATH11K_FLUSH_TIMEOUT (5 * HZ)
#define ATH11K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ)

struct ath11k_vdev_stop_status {
	bool stop_in_progress;
@@ -512,6 +513,7 @@ struct ath11k {
	int last_wmi_vdev_start_status;
	struct ath11k_vdev_stop_status vdev_stop_status;
	struct completion vdev_setup_done;
	struct completion vdev_delete_done;

	int num_peers;
	int max_num_peers;
+22 −7
Original line number Diff line number Diff line
@@ -4660,6 +4660,7 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
	struct ath11k *ar = hw->priv;
	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
	struct ath11k_base *ab = ar->ab;
	unsigned long time_left;
	int ret;
	int i;

@@ -4668,10 +4669,6 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
	ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
		   arvif->vdev_id);

	spin_lock_bh(&ar->data_lock);
	list_del(&arvif->list);
	spin_unlock_bh(&ar->data_lock);

	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
		ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
		if (ret)
@@ -4679,16 +4676,33 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
				    arvif->vdev_id, ret);
	}

	reinit_completion(&ar->vdev_delete_done);

	ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
	if (ret)
	if (ret) {
		ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n",
			    arvif->vdev_id, ret);
		goto err_vdev_del;
	}

	time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
						ATH11K_VDEV_DELETE_TIMEOUT_HZ);
	if (time_left == 0) {
		ath11k_warn(ab, "Timeout in receiving vdev delete response\n");
		goto err_vdev_del;
	}

	ab->free_vdev_map |= 1LL << (arvif->vdev_id);
	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
	ar->num_created_vdevs--;

	ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
		   vif->addr, arvif->vdev_id);
	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
	ab->free_vdev_map |= 1LL << (arvif->vdev_id);

err_vdev_del:
	spin_lock_bh(&ar->data_lock);
	list_del(&arvif->list);
	spin_unlock_bh(&ar->data_lock);

	ath11k_peer_cleanup(ar, arvif->vdev_id);

@@ -6454,6 +6468,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
		INIT_LIST_HEAD(&ar->ppdu_stats_info);
		mutex_init(&ar->conf_mutex);
		init_completion(&ar->vdev_setup_done);
		init_completion(&ar->vdev_delete_done);
		init_completion(&ar->peer_assoc_done);
		init_completion(&ar->install_key_done);
		init_completion(&ar->bss_survey_done);
+61 −1
Original line number Diff line number Diff line
@@ -126,6 +126,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
		.min_len = sizeof(struct wmi_fils_discovery_event) },
	[WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT] = {
		.min_len = sizeof(struct wmi_probe_resp_tx_status_event) },
	[WMI_TAG_VDEV_DELETE_RESP_EVENT] = {
		.min_len = sizeof(struct wmi_vdev_delete_resp_event) },
};

#define PRIMAP(_hw_mode_) \
@@ -4379,6 +4381,34 @@ static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *
	return 0;
}

static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab,
					struct sk_buff *skb,
					u32 *vdev_id)
{
	const void **tb;
	const struct wmi_vdev_delete_resp_event *ev;
	int ret;

	tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
	if (IS_ERR(tb)) {
		ret = PTR_ERR(tb);
		ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
		return ret;
	}

	ev = tb[WMI_TAG_VDEV_DELETE_RESP_EVENT];
	if (!ev) {
		ath11k_warn(ab, "failed to fetch vdev delete resp ev");
		kfree(tb);
		return -EPROTO;
	}

	*vdev_id = ev->vdev_id;

	kfree(tb);
	return 0;
}

static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab, void *evt_buf,
					u32 len, u32 *vdev_id,
					u32 *tx_status)
@@ -5711,6 +5741,34 @@ static void ath11k_peer_delete_resp_event(struct ath11k_base *ab, struct sk_buff
	 */
}

static void ath11k_vdev_delete_resp_event(struct ath11k_base *ab,
					  struct sk_buff *skb)
{
	struct ath11k *ar;
	u32 vdev_id = 0;

	if (ath11k_pull_vdev_del_resp_ev(ab, skb, &vdev_id) != 0) {
		ath11k_warn(ab, "failed to extract vdev delete resp");
		return;
	}

	rcu_read_lock();
	ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id);
	if (!ar) {
		ath11k_warn(ab, "invalid vdev id in vdev delete resp ev %d",
			    vdev_id);
		rcu_read_unlock();
		return;
	}

	complete(&ar->vdev_delete_done);

	rcu_read_unlock();

	ath11k_dbg(ab, ATH11K_DBG_WMI, "vdev delete resp for vdev id %d\n",
		   vdev_id);
}

static inline const char *ath11k_wmi_vdev_resp_print(u32 vdev_resp_status)
{
	switch (vdev_resp_status) {
@@ -6722,7 +6780,6 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
		break;
	/* add Unsupported events here */
	case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
	case WMI_VDEV_DELETE_RESP_EVENTID:
	case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
	case WMI_TWT_ENABLE_EVENTID:
	case WMI_TWT_DISABLE_EVENTID:
@@ -6733,6 +6790,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
	case WMI_PDEV_DFS_RADAR_DETECTION_EVENTID:
		ath11k_wmi_pdev_dfs_radar_detected_event(ab, skb);
		break;
	case WMI_VDEV_DELETE_RESP_EVENTID:
		ath11k_vdev_delete_resp_event(ab, skb);
		break;
	/* TODO: Add remaining events */
	default:
		ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
+4 −0
Original line number Diff line number Diff line
@@ -4018,6 +4018,10 @@ struct wmi_regulatory_rule_struct {
	u32  flag_info;
};

struct wmi_vdev_delete_resp_event {
	u32 vdev_id;
} __packed;

struct wmi_peer_delete_resp_event {
	u32 vdev_id;
	struct wmi_mac_addr peer_macaddr;