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

Commit 168168f2 authored by Lior David's avatar Lior David Committed by Maya Erez
Browse files

wil6210: multiple VIFs support for connections and data path



Track the connection status per-VIF.
The data path code is also updated to support multiple VIFs.
This includes RX and TX VRING management, NAPI poll loops,
RX reordering and related code.
Power management code used to check if the main interface
is up or based on connection state of the main interface,
adapt this code to take all VIFs into account.

Change-Id: I69c4645f884b68bc1e538619130d0b1024546e5a
Signed-off-by: default avatarLior David <liord@codeaurora.org>
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Git-commit: 5bd60982
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git


Signed-off-by: default avatarAlexei Avshalom Lazar <ailizaro@codeaurora.org>
parent 6b4a9d37
Loading
Loading
Loading
Loading
+15 −17
Original line number Original line Diff line number Diff line
@@ -391,7 +391,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
	sinfo->tx_packets = stats->tx_packets;
	sinfo->tx_packets = stats->tx_packets;
	sinfo->tx_failed = stats->tx_errors;
	sinfo->tx_failed = stats->tx_errors;


	if (test_bit(wil_status_fwconnected, wil->status)) {
	if (test_bit(wil_vif_fwconnected, vif->status)) {
		sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
		sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
		if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING,
		if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING,
			     wil->fw_capabilities))
			     wil->fw_capabilities))
@@ -562,11 +562,10 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
			return ERR_PTR(-EINVAL);
			return ERR_PTR(-EINVAL);
		}
		}


		vif = kzalloc(sizeof(*vif), GFP_KERNEL);
		p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL);
		if (!vif)
		if (!p2p_wdev)
			return ERR_PTR(-ENOMEM);
			return ERR_PTR(-ENOMEM);


		p2p_wdev = vif_to_wdev(vif);
		p2p_wdev->iftype = type;
		p2p_wdev->iftype = type;
		p2p_wdev->wiphy = wiphy;
		p2p_wdev->wiphy = wiphy;
		/* use our primary ethernet address */
		/* use our primary ethernet address */
@@ -976,8 +975,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
	wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
	wil_print_connect_params(wil, sme);
	wil_print_connect_params(wil, sme);


	if (test_bit(wil_status_fwconnecting, wil->status) ||
	if (test_bit(wil_vif_fwconnecting, vif->status) ||
	    test_bit(wil_status_fwconnected, wil->status))
	    test_bit(wil_vif_fwconnected, vif->status))
		return -EALREADY;
		return -EALREADY;


	if (sme->ie_len > WMI_MAX_IE_LEN) {
	if (sme->ie_len > WMI_MAX_IE_LEN) {
@@ -1081,18 +1080,19 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	ether_addr_copy(conn.bssid, bss->bssid);
	ether_addr_copy(conn.bssid, bss->bssid);
	ether_addr_copy(conn.dst_mac, bss->bssid);
	ether_addr_copy(conn.dst_mac, bss->bssid);


	set_bit(wil_status_fwconnecting, wil->status);
	set_bit(wil_vif_fwconnecting, vif->status);


	rc = wmi_send(wil, WMI_CONNECT_CMDID, vif->mid, &conn, sizeof(conn));
	rc = wmi_send(wil, WMI_CONNECT_CMDID, vif->mid, &conn, sizeof(conn));
	if (rc == 0) {
	if (rc == 0) {
		netif_carrier_on(ndev);
		netif_carrier_on(ndev);
		if (!wil_has_other_active_ifaces(wil, ndev, false, true))
			wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
			wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
		vif->bss = bss;
		vif->bss = bss;
		/* Connect can take lots of time */
		/* Connect can take lots of time */
		mod_timer(&vif->connect_timer,
		mod_timer(&vif->connect_timer,
			  jiffies + msecs_to_jiffies(5000));
			  jiffies + msecs_to_jiffies(5000));
	} else {
	} else {
		clear_bit(wil_status_fwconnecting, wil->status);
		clear_bit(wil_vif_fwconnecting, vif->status);
	}
	}


 out:
 out:
@@ -1112,8 +1112,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
	wil_dbg_misc(wil, "disconnect: reason=%d, mid=%d\n",
	wil_dbg_misc(wil, "disconnect: reason=%d, mid=%d\n",
		     reason_code, vif->mid);
		     reason_code, vif->mid);


	if (!(test_bit(wil_status_fwconnecting, wil->status) ||
	if (!(test_bit(wil_vif_fwconnecting, vif->status) ||
	      test_bit(wil_status_fwconnected, wil->status))) {
	      test_bit(wil_vif_fwconnected, vif->status))) {
		wil_err(wil, "Disconnect was called while disconnected\n");
		wil_err(wil, "Disconnect was called while disconnected\n");
		return 0;
		return 0;
	}
	}
@@ -2017,7 +2017,7 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy,
	mutex_lock(&wil->mutex);
	mutex_lock(&wil->mutex);
	mutex_lock(&wil->vif_mutex);
	mutex_lock(&wil->vif_mutex);
	wil_p2p_stop_radio_operations(wil);
	wil_p2p_stop_radio_operations(wil);
	wil_abort_scan(ndev_to_vif(wil->main_ndev), true);
	wil_abort_scan_all_vifs(wil, true);
	mutex_unlock(&wil->vif_mutex);
	mutex_unlock(&wil->vif_mutex);
	mutex_unlock(&wil->mutex);
	mutex_unlock(&wil->mutex);


@@ -2312,7 +2312,6 @@ void wil_cfg80211_deinit(struct wil6210_priv *wil)
void wil_p2p_wdev_free(struct wil6210_priv *wil)
void wil_p2p_wdev_free(struct wil6210_priv *wil)
{
{
	struct wireless_dev *p2p_wdev;
	struct wireless_dev *p2p_wdev;
	struct wil6210_vif *vif;


	mutex_lock(&wil->vif_mutex);
	mutex_lock(&wil->vif_mutex);
	p2p_wdev = wil->p2p_wdev;
	p2p_wdev = wil->p2p_wdev;
@@ -2321,8 +2320,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil)
	mutex_unlock(&wil->vif_mutex);
	mutex_unlock(&wil->vif_mutex);
	if (p2p_wdev) {
	if (p2p_wdev) {
		cfg80211_unregister_wdev(p2p_wdev);
		cfg80211_unregister_wdev(p2p_wdev);
		vif = wdev_to_vif(wil, p2p_wdev);
		kfree(p2p_wdev);
		kfree(vif);
	}
	}
}
}


@@ -2616,7 +2614,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
			return -ENOENT;
			return -ENOENT;
		}
		}
	} else {
	} else {
		if (test_bit(wil_status_fwconnected, wil->status)) {
		if (test_bit(wil_vif_fwconnected, vif->status)) {
			wil_err(wil, "must specify MAC address when connected\n");
			wil_err(wil, "must specify MAC address when connected\n");
			return -EINVAL;
			return -EINVAL;
		}
		}
@@ -2743,7 +2741,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
			cid = -1;
			cid = -1;
		}
		}
	} else {
	} else {
		if (test_bit(wil_status_fwconnected, wil->status)) {
		if (test_bit(wil_vif_fwconnected, vif->status)) {
			wil_err(wil, "must specify MAC address when connected\n");
			wil_err(wil, "must specify MAC address when connected\n");
			return -EINVAL;
			return -EINVAL;
		}
		}
+16 −4
Original line number Original line Diff line number Diff line
@@ -1246,12 +1246,13 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
{
{
	struct wil6210_priv *wil = s->private;
	struct wil6210_priv *wil = s->private;
	struct station_info sinfo;
	struct station_info sinfo;
	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
	int i, rc;
	int i, rc;


	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
		struct wil_sta_info *p = &wil->sta[i];
		struct wil_sta_info *p = &wil->sta[i];
		char *status = "unknown";
		char *status = "unknown";
		struct wil6210_vif *vif;
		u8 mid;


		switch (p->status) {
		switch (p->status) {
		case wil_sta_unused:
		case wil_sta_unused:
@@ -1264,9 +1265,15 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
			status = "connected";
			status = "connected";
			break;
			break;
		}
		}
		seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
		seq_printf(s, "[%d][MID %d] %pM %s\n",
			   i, mid, p->addr, status);


		if (p->status == wil_sta_connected) {
		if (p->status != wil_sta_connected)
			continue;

		vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
		if (vif) {
			rc = wil_cid_fill_sinfo(vif, i, &sinfo);
			rc = wil_cid_fill_sinfo(vif, i, &sinfo);
			if (rc)
			if (rc)
				return rc;
				return rc;
@@ -1274,6 +1281,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
			seq_printf(s, "  Tx_mcs = %d\n", sinfo.txrate.mcs);
			seq_printf(s, "  Tx_mcs = %d\n", sinfo.txrate.mcs);
			seq_printf(s, "  Rx_mcs = %d\n", sinfo.rxrate.mcs);
			seq_printf(s, "  Rx_mcs = %d\n", sinfo.rxrate.mcs);
			seq_printf(s, "  SQ     = %d\n", sinfo.signal);
			seq_printf(s, "  SQ     = %d\n", sinfo.signal);
		} else {
			seq_puts(s, "  INVALID MID\n");
		}
		}
	}
	}


@@ -1465,6 +1474,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
		struct wil_sta_info *p = &wil->sta[i];
		struct wil_sta_info *p = &wil->sta[i];
		char *status = "unknown";
		char *status = "unknown";
		u8 aid = 0;
		u8 aid = 0;
		u8 mid;


		switch (p->status) {
		switch (p->status) {
		case wil_sta_unused:
		case wil_sta_unused:
@@ -1478,7 +1488,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
			aid = p->aid;
			aid = p->aid;
			break;
			break;
		}
		}
		seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid);
		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
		seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
			   mid, aid);


		if (p->status == wil_sta_connected) {
		if (p->status == wil_sta_connected) {
			spin_lock_bh(&p->tid_rx_lock);
			spin_lock_bh(&p->tid_rx_lock);
+1 −1
Original line number Original line Diff line number Diff line
@@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)


void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
{
{
	bool unmask_rx_htrsh = test_bit(wil_status_fwconnected, wil->status);
	bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;


	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
	      unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
	      unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
+55 −23
Original line number Original line Diff line number Diff line
@@ -175,6 +175,15 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
		     cid, sta->mid, sta->status);
		     cid, sta->mid, sta->status);
	/* inform upper/lower layers */
	/* inform upper/lower layers */
	if (sta->status != wil_sta_unused) {
	if (sta->status != wil_sta_unused) {
		if (vif->mid != sta->mid) {
			wil_err(wil, "STA MID mismatch with VIF MID(%d)\n",
				vif->mid);
			/* let FW override sta->mid but be more strict with
			 * user space requests
			 */
			if (!from_event)
				return;
		}
		if (!from_event) {
		if (!from_event) {
			bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
			bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
						disable_ap_sme : false;
						disable_ap_sme : false;
@@ -278,32 +287,35 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_P2P_CLIENT:
		wil_bcast_fini(vif);
		wil_bcast_fini(vif);
		wil_update_net_queues_bh(wil, NULL, true);
		wil_update_net_queues_bh(wil, vif, NULL, true);
		netif_carrier_off(ndev);
		netif_carrier_off(ndev);
		if (!wil_has_other_active_ifaces(wil, ndev, false, true))
			wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
			wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);


		if (test_bit(wil_status_fwconnected, wil->status)) {
		if (test_and_clear_bit(wil_vif_fwconnected, vif->status)) {
			clear_bit(wil_status_fwconnected, wil->status);
			atomic_dec(&wil->connected_vifs);
			cfg80211_disconnected(ndev, reason_code,
			cfg80211_disconnected(ndev, reason_code,
					      NULL, 0,
					      NULL, 0,
					      vif->locally_generated_disc,
					      vif->locally_generated_disc,
					      GFP_KERNEL);
					      GFP_KERNEL);
			vif->locally_generated_disc = false;
			vif->locally_generated_disc = false;
		} else if (test_bit(wil_status_fwconnecting, wil->status)) {
		} else if (test_bit(wil_vif_fwconnecting, vif->status)) {
			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
						WLAN_STATUS_UNSPECIFIED_FAILURE,
						WLAN_STATUS_UNSPECIFIED_FAILURE,
						GFP_KERNEL);
						GFP_KERNEL);
			vif->bss = NULL;
			vif->bss = NULL;
		}
		}
		clear_bit(wil_status_fwconnecting, wil->status);
		clear_bit(wil_vif_fwconnecting, vif->status);
		break;
		break;
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
	case NL80211_IFTYPE_P2P_GO:
		if (!wil_vif_is_connected(wil, vif->mid)) {
		if (!wil_vif_is_connected(wil, vif->mid)) {
			wil_update_net_queues_bh(wil, NULL, true);
			wil_update_net_queues_bh(wil, vif, NULL, true);
			clear_bit(wil_status_fwconnected, wil->status);
			if (test_and_clear_bit(wil_vif_fwconnected,
					       vif->status))
				atomic_dec(&wil->connected_vifs);
		} else {
		} else {
			wil_update_net_queues_bh(wil, NULL, false);
			wil_update_net_queues_bh(wil, vif, NULL, false);
		}
		}
		break;
		break;
	default:
	default:
@@ -323,11 +335,11 @@ void wil_disconnect_worker(struct work_struct *work)
		struct wmi_disconnect_event evt;
		struct wmi_disconnect_event evt;
	} __packed reply;
	} __packed reply;


	if (test_bit(wil_status_fwconnected, wil->status))
	if (test_bit(wil_vif_fwconnected, vif->status))
		/* connect succeeded after all */
		/* connect succeeded after all */
		return;
		return;


	if (!test_bit(wil_status_fwconnecting, wil->status))
	if (!test_bit(wil_vif_fwconnecting, vif->status))
		/* already disconnected */
		/* already disconnected */
		return;
		return;


@@ -339,11 +351,11 @@ void wil_disconnect_worker(struct work_struct *work)
		return;
		return;
	}
	}


	wil_update_net_queues_bh(wil, NULL, true);
	wil_update_net_queues_bh(wil, vif, NULL, true);
	netif_carrier_off(ndev);
	netif_carrier_off(ndev);
	cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
	cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
				WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
				WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
	clear_bit(wil_status_fwconnecting, wil->status);
	clear_bit(wil_vif_fwconnecting, vif->status);
}
}


static int wil_wait_for_recovery(struct wil6210_priv *wil)
static int wil_wait_for_recovery(struct wil6210_priv *wil)
@@ -1096,6 +1108,20 @@ void wil_abort_scan(struct wil6210_vif *vif, bool sync)
	}
	}
}
}


void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync)
{
	int i;

	lockdep_assert_held(&wil->vif_mutex);

	for (i = 0; i < wil->max_vifs; i++) {
		struct wil6210_vif *vif = wil->vifs[i];

		if (vif)
			wil_abort_scan(vif, sync);
	}
}

int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile)
int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile)
{
{
	int rc;
	int rc;
@@ -1148,6 +1174,7 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
		vif = wil->vifs[i];
		vif = wil->vifs[i];
		if (!vif)
		if (!vif)
			continue;
			continue;
		vif->ap_isolate = 0;
		if (vif->mid) {
		if (vif->mid) {
			ndev = vif_to_ndev(vif);
			ndev = vif_to_ndev(vif);
			wdev = vif_to_wdev(vif);
			wdev = vif_to_wdev(vif);
@@ -1171,10 +1198,10 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
 */
 */
int wil_reset(struct wil6210_priv *wil, bool load_fw)
int wil_reset(struct wil6210_priv *wil, bool load_fw)
{
{
	int rc;
	int rc, i;
	unsigned long status_flags = BIT(wil_status_resetting);
	unsigned long status_flags = BIT(wil_status_resetting);
	int no_flash;
	int no_flash;
	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
	struct wil6210_vif *vif;


	wil_dbg_misc(wil, "reset\n");
	wil_dbg_misc(wil, "reset\n");


@@ -1226,17 +1253,23 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
		goto out;
		goto out;
	}
	}


	mutex_lock(&wil->vif_mutex);
	wil_abort_scan_all_vifs(wil, false);
	mutex_unlock(&wil->vif_mutex);

	for (i = 0; i < wil->max_vifs; i++) {
		vif = wil->vifs[i];
		if (vif) {
			cancel_work_sync(&vif->disconnect_worker);
			cancel_work_sync(&vif->disconnect_worker);
	wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
			wil6210_disconnect(vif, NULL,
					   WLAN_REASON_DEAUTH_LEAVING, false);
		}
	}
	wil_bcast_fini_all(wil);
	wil_bcast_fini_all(wil);


	/* Disable device led before reset*/
	/* Disable device led before reset*/
	wmi_led_cfg(wil, false);
	wmi_led_cfg(wil, false);


	mutex_lock(&wil->vif_mutex);
	wil_abort_scan(vif, false);
	mutex_unlock(&wil->vif_mutex);

	/* prevent NAPI from being scheduled and prevent wmi commands */
	/* prevent NAPI from being scheduled and prevent wmi commands */
	mutex_lock(&wil->wmi_mutex);
	mutex_lock(&wil->wmi_mutex);
	if (test_bit(wil_status_suspending, wil->status))
	if (test_bit(wil_status_suspending, wil->status))
@@ -1306,7 +1339,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
	}
	}


	/* init after reset */
	/* init after reset */
	vif->ap_isolate = 0;
	reinit_completion(&wil->wmi_ready);
	reinit_completion(&wil->wmi_ready);
	reinit_completion(&wil->wmi_call);
	reinit_completion(&wil->wmi_call);
	reinit_completion(&wil->halp.comp);
	reinit_completion(&wil->halp.comp);
@@ -1467,7 +1499,7 @@ int __wil_down(struct wil6210_priv *wil)


	mutex_lock(&wil->vif_mutex);
	mutex_lock(&wil->vif_mutex);
	wil_p2p_stop_radio_operations(wil);
	wil_p2p_stop_radio_operations(wil);
	wil_abort_scan(ndev_to_vif(wil->main_ndev), false);
	wil_abort_scan_all_vifs(wil, false);
	mutex_unlock(&wil->vif_mutex);
	mutex_unlock(&wil->vif_mutex);


	return wil_reset(wil, false);
	return wil_reset(wil, false);
+42 −5
Original line number Original line Diff line number Diff line
@@ -48,6 +48,7 @@ bool wil_has_other_active_ifaces(struct wil6210_priv *wil,


bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok)
bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok)
{
{
	/* use NULL ndev argument to check all interfaces */
	return wil_has_other_active_ifaces(wil, NULL, up, ok);
	return wil_has_other_active_ifaces(wil, NULL, up, ok);
}
}


@@ -143,11 +144,19 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
		struct vring *vring = &wil->vring_tx[i];
		struct vring *vring = &wil->vring_tx[i];
		struct vring_tx_data *txdata = &wil->vring_tx_data[i];
		struct vring_tx_data *txdata = &wil->vring_tx_data[i];
		struct wil6210_vif *vif;

		if (!vring->va || !txdata->enabled ||
		    txdata->mid >= wil->max_vifs)
			continue;


		if (!vring->va || !txdata->enabled)
		vif = wil->vifs[txdata->mid];
		if (unlikely(!vif)) {
			wil_dbg_txrx(wil, "Invalid MID %d\n", txdata->mid);
			continue;
			continue;
		}


		tx_done += wil_tx_complete(wil, i);
		tx_done += wil_tx_complete(vif, i);
	}
	}


	if (tx_done < budget) {
	if (tx_done < budget) {
@@ -246,7 +255,10 @@ static void wil_vif_init(struct wil6210_vif *vif)
	INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
	INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);


	INIT_LIST_HEAD(&vif->probe_client_pending);
	INIT_LIST_HEAD(&vif->probe_client_pending);

	wil_ftm_init(vif);
	wil_ftm_init(vif);

	vif->net_queue_stopped = 1;
}
}


static u8 wil_vif_find_free_mid(struct wil6210_priv *wil)
static u8 wil_vif_find_free_mid(struct wil6210_priv *wil)
@@ -422,12 +434,14 @@ int wil_if_add(struct wil6210_priv *wil)
		return rc;
		return rc;
	}
	}


	netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
	init_dummy_netdev(&wil->napi_ndev);
	netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
		       WIL6210_NAPI_BUDGET);
		       WIL6210_NAPI_BUDGET);
	netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
	netif_tx_napi_add(&wil->napi_ndev,
			  &wil->napi_tx, wil6210_netdev_poll_tx,
			  WIL6210_NAPI_BUDGET);
			  WIL6210_NAPI_BUDGET);


	wil_update_net_queues_bh(wil, NULL, true);
	wil_update_net_queues_bh(wil, vif, NULL, true);


	rtnl_lock();
	rtnl_lock();
	rc = wil_vif_add(wil, vif);
	rc = wil_vif_add(wil, vif);
@@ -466,10 +480,29 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
	 */
	 */
	unregister_netdevice(ndev);
	unregister_netdevice(ndev);


	mutex_lock(&wil->mutex);
	wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
	mutex_unlock(&wil->mutex);

	if (any_active && vif->mid != 0)
	if (any_active && vif->mid != 0)
		wmi_port_delete(wil, vif->mid);
		wmi_port_delete(wil, vif->mid);


	/* make sure no one is accessing the VIF before removing */
	mutex_lock(&wil->vif_mutex);
	wil->vifs[mid] = NULL;
	wil->vifs[mid] = NULL;
	/* ensure NAPI code will see the NULL VIF */
	wmb();
	if (test_bit(wil_status_napi_en, wil->status)) {
		napi_synchronize(&wil->napi_rx);
		napi_synchronize(&wil->napi_tx);
	}
	mutex_unlock(&wil->vif_mutex);

	flush_work(&wil->wmi_event_worker);
	del_timer_sync(&vif->connect_timer);
	cancel_work_sync(&vif->disconnect_worker);
	wil_probe_client_flush(vif);
	cancel_work_sync(&vif->probe_client_worker);
	/* for VIFs, ndev will be freed by destructor after RTNL is unlocked.
	/* for VIFs, ndev will be freed by destructor after RTNL is unlocked.
	 * the main interface will be freed in wil_if_free, we need to keep it
	 * the main interface will be freed in wil_if_free, we need to keep it
	 * a bit longer so logging macros will work.
	 * a bit longer so logging macros will work.
@@ -486,5 +519,9 @@ void wil_if_remove(struct wil6210_priv *wil)
	rtnl_lock();
	rtnl_lock();
	wil_vif_remove(wil, 0);
	wil_vif_remove(wil, 0);
	rtnl_unlock();
	rtnl_unlock();

	netif_napi_del(&wil->napi_tx);
	netif_napi_del(&wil->napi_rx);

	wiphy_unregister(wdev->wiphy);
	wiphy_unregister(wdev->wiphy);
}
}
Loading