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

Commit 4aebd3bd authored by Lior David's avatar Lior David Committed by Kalle Valo
Browse files

wil6210: add support for adding and removing virtual interfaces



Add generic support in cfg80211 operations add_virtual_intf
and del_virtual_intf for adding/removing VIFs of any
interface type, and fix change_virtual_intf to allow changing
the interface type of a VIF. Previously these operations
only worked for the P2P_DEVICE interface which is not a real
VIF(it is management-only and shares radio with the main
interface).
Currently the interface combination is validated, the VIF is
added/removed in the firmware and the appropriate net/wireless
device is also added/removed.
Added minimal support for proper interface up/down and module
unload but most operations still work only on the main interface.

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>
parent e00243fa
Loading
Loading
Loading
Loading
+184 −25
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/etherdevice.h>
#include <linux/moduleparam.h>
#include <net/netlink.h>
#include <net/cfg80211.h>
#include "wil6210.h"
#include "wmi.h"
#include "fw.h"
@@ -418,6 +419,53 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
	mutex_unlock(&wil->mutex);
}

static int wil_cfg80211_validate_add_iface(struct wil6210_priv *wil,
					   enum nl80211_iftype new_type)
{
	int i;
	struct wireless_dev *wdev;
	struct iface_combination_params params = {
		.num_different_channels = 1,
	};

	for (i = 0; i < wil->max_vifs; i++) {
		if (wil->vifs[i]) {
			wdev = vif_to_wdev(wil->vifs[i]);
			params.iftype_num[wdev->iftype]++;
		}
	}
	params.iftype_num[new_type]++;
	return cfg80211_check_combinations(wil->wiphy, &params);
}

static int wil_cfg80211_validate_change_iface(struct wil6210_priv *wil,
					      struct wil6210_vif *vif,
					      enum nl80211_iftype new_type)
{
	int i, ret = 0;
	struct wireless_dev *wdev;
	struct iface_combination_params params = {
		.num_different_channels = 1,
	};
	bool check_combos = false;

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

		if (vif_pos && vif != vif_pos) {
			wdev = vif_to_wdev(vif_pos);
			params.iftype_num[wdev->iftype]++;
			check_combos = true;
		}
	}

	if (check_combos) {
		params.iftype_num[new_type]++;
		ret = cfg80211_check_combinations(wil->wiphy, &params);
	}
	return ret;
}

static struct wireless_dev *
wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
		       unsigned char name_assign_type,
@@ -425,17 +473,18 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
		       struct vif_params *params)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct net_device *ndev = wil->main_ndev;
	struct net_device *ndev_main = wil->main_ndev, *ndev;
	struct wil6210_vif *vif;
	struct wireless_dev *p2p_wdev;

	wil_dbg_misc(wil, "add_iface\n");
	struct wireless_dev *p2p_wdev, *wdev;
	int rc;

	if (type != NL80211_IFTYPE_P2P_DEVICE) {
		wil_err(wil, "unsupported iftype %d\n", type);
		return ERR_PTR(-EINVAL);
	}
	wil_dbg_misc(wil, "add_iface, type %d\n", type);

	/* P2P device is not a real virtual interface, it is a management-only
	 * interface that shares the main interface.
	 * Skip concurrency checks here.
	 */
	if (type == NL80211_IFTYPE_P2P_DEVICE) {
		if (wil->p2p_wdev) {
			wil_err(wil, "P2P_DEVICE interface already created\n");
			return ERR_PTR(-EINVAL);
@@ -445,35 +494,117 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
		if (!vif)
			return ERR_PTR(-ENOMEM);

	p2p_wdev = &vif->wdev;
		p2p_wdev = vif_to_wdev(vif);
		p2p_wdev->iftype = type;
		p2p_wdev->wiphy = wiphy;
		/* use our primary ethernet address */
	ether_addr_copy(p2p_wdev->address, ndev->perm_addr);
		ether_addr_copy(p2p_wdev->address, ndev_main->perm_addr);

		wil->p2p_wdev = p2p_wdev;

		return p2p_wdev;
	}

	if (!wil->wiphy->n_iface_combinations) {
		wil_err(wil, "virtual interfaces not supported\n");
		return ERR_PTR(-EINVAL);
	}

	rc = wil_cfg80211_validate_add_iface(wil, type);
	if (rc) {
		wil_err(wil, "iface validation failed, err=%d\n", rc);
		return ERR_PTR(rc);
	}

	vif = wil_vif_alloc(wil, name, name_assign_type, type);
	if (IS_ERR(vif))
		return ERR_CAST(vif);

	ndev = vif_to_ndev(vif);
	ether_addr_copy(ndev->perm_addr, ndev_main->perm_addr);
	if (is_valid_ether_addr(params->macaddr)) {
		ether_addr_copy(ndev->dev_addr, params->macaddr);
	} else {
		ether_addr_copy(ndev->dev_addr, ndev_main->perm_addr);
		ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << vif->mid)) |
			0x2; /* locally administered */
	}
	wdev = vif_to_wdev(vif);
	ether_addr_copy(wdev->address, ndev->dev_addr);

	rc = wil_vif_add(wil, vif);
	if (rc)
		goto out;

	wil_info(wil, "added VIF, mid %d iftype %d MAC %pM\n",
		 vif->mid, type, wdev->address);
	return wdev;
out:
	wil_vif_free(vif);
	return ERR_PTR(rc);
}

int wil_vif_prepare_stop(struct wil6210_priv *wil, struct wil6210_vif *vif)
{
	struct wireless_dev *wdev = vif_to_wdev(vif);
	struct net_device *ndev;
	int rc;

	if (wdev->iftype != NL80211_IFTYPE_AP)
		return 0;

	ndev = vif_to_ndev(vif);
	if (netif_carrier_ok(ndev)) {
		rc = wmi_pcp_stop(vif);
		if (rc) {
			wil_info(wil, "failed to stop AP, status %d\n",
				 rc);
			/* continue */
		}
		netif_carrier_off(ndev);
	}

	return 0;
}

static int wil_cfg80211_del_iface(struct wiphy *wiphy,
				  struct wireless_dev *wdev)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
	int rc;

	wil_dbg_misc(wil, "del_iface\n");

	if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
		if (wdev != wil->p2p_wdev) {
		wil_err(wil, "delete of incorrect interface 0x%p\n", wdev);
			wil_err(wil, "delete of incorrect interface 0x%p\n",
				wdev);
			return -EINVAL;
		}

		wil_cfg80211_stop_p2p_device(wiphy, wdev);
		wil_p2p_wdev_free(wil);

		return 0;
	}

	if (vif->mid == 0) {
		wil_err(wil, "cannot remove the main interface\n");
		return -EINVAL;
	}

	rc = wil_vif_prepare_stop(wil, vif);
	if (rc)
		goto out;

	wil_info(wil, "deleted VIF, mid %d iftype %d MAC %pM\n",
		 vif->mid, wdev->iftype, wdev->address);

	wil_vif_remove(wil, vif->mid);
out:
	return rc;
}

static int wil_cfg80211_change_iface(struct wiphy *wiphy,
				     struct net_device *ndev,
				     enum nl80211_iftype type,
@@ -486,7 +617,19 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,

	wil_dbg_misc(wil, "change_iface: type=%d\n", type);

	if (netif_running(ndev) && !wil_is_recovery_blocked(wil)) {
	if (wiphy->n_iface_combinations) {
		rc = wil_cfg80211_validate_change_iface(wil, vif, type);
		if (rc) {
			wil_err(wil, "iface validation failed, err=%d\n", rc);
			return rc;
		}
	}

	/* do not reset FW when there are active VIFs,
	 * because it can cause significant disruption
	 */
	if (!wil_has_other_up_ifaces(wil, ndev) &&
	    netif_running(ndev) && !wil_is_recovery_blocked(wil)) {
		wil_dbg_misc(wil, "interface is up. resetting...\n");
		mutex_lock(&wil->mutex);
		__wil_down(wil);
@@ -511,8 +654,17 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
		return -EOPNOTSUPP;
	}

	wdev->iftype = type;
	if (vif->mid != 0 && wil_has_up_ifaces(wil)) {
		wil_vif_prepare_stop(wil, vif);
		rc = wmi_port_delete(wil, vif->mid);
		if (rc)
			return rc;
		rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr, type);
		if (rc)
			return rc;
	}

	wdev->iftype = type;
	return 0;
}

@@ -2007,6 +2159,13 @@ int wil_cfg80211_iface_combinations_from_fw(
		combo = (struct wil_fw_concurrency_combo *)limit;
	}

	wil_dbg_misc(wil, "multiple VIFs supported, n_mids %d\n", conc->n_mids);
	wil->max_vifs = conc->n_mids + 1; /* including main interface */
	if (wil->max_vifs > WIL_MAX_VIFS) {
		wil_info(wil, "limited number of VIFs supported(%d, FW %d)\n",
			 WIL_MAX_VIFS, wil->max_vifs);
		wil->max_vifs = WIL_MAX_VIFS;
	}
	wiphy->n_iface_combinations = n_combos;
	wiphy->iface_combinations = iface_combinations;
	return 0;
+34 −0
Original line number Diff line number Diff line
@@ -565,6 +565,7 @@ int wil_priv_init(struct wil6210_priv *wil)
	wil->vring_idle_trsh = 16;

	wil->reply_mid = U8_MAX;
	wil->max_vifs = 1;

	return 0;

@@ -1115,6 +1116,33 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
	}
}

static int wil_restore_vifs(struct wil6210_priv *wil)
{
	struct wil6210_vif *vif;
	struct net_device *ndev;
	struct wireless_dev *wdev;
	int i, rc;

	for (i = 0; i < wil->max_vifs; i++) {
		vif = wil->vifs[i];
		if (!vif)
			continue;
		if (vif->mid) {
			ndev = vif_to_ndev(vif);
			wdev = vif_to_wdev(vif);
			rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr,
					       wdev->iftype);
			if (rc) {
				wil_err(wil, "fail to restore VIF %d type %d, rc %d\n",
					i, wdev->iftype, rc);
				return rc;
			}
		}
	}

	return 0;
}

/*
 * We reset all the structures, and we reset the UMAC.
 * After calling this routine, you're expected to reload
@@ -1277,6 +1305,12 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
			return rc;
		}

		rc = wil_restore_vifs(wil);
		if (rc) {
			wil_err(wil, "failed to restore vifs, rc %d\n", rc);
			return rc;
		}

		wil_collect_fw_info(wil);

		if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
+143 −20
Original line number Diff line number Diff line
@@ -16,13 +16,38 @@
 */

#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include "wil6210.h"
#include "txrx.h"

bool wil_has_other_up_ifaces(struct wil6210_priv *wil,
			     struct net_device *ndev)
{
	int i;
	struct wil6210_vif *vif;
	struct net_device *ndev_i;

	for (i = 0; i < wil->max_vifs; i++) {
		vif = wil->vifs[i];
		if (vif) {
			ndev_i = vif_to_ndev(vif);
			if (ndev_i != ndev && ndev_i->flags & IFF_UP)
				return true;
		}
	}

	return false;
}

bool wil_has_up_ifaces(struct wil6210_priv *wil)
{
	return wil_has_other_up_ifaces(wil, NULL);
}

static int wil_open(struct net_device *ndev)
{
	struct wil6210_priv *wil = ndev_to_wil(ndev);
	int rc;
	int rc = 0;

	wil_dbg_misc(wil, "open\n");

@@ -32,6 +57,8 @@ static int wil_open(struct net_device *ndev)
		return -EINVAL;
	}

	if (!wil_has_other_up_ifaces(wil, ndev)) {
		wil_dbg_misc(wil, "open, first iface\n");
		rc = wil_pm_runtime_get(wil);
		if (rc < 0)
			return rc;
@@ -39,6 +66,7 @@ static int wil_open(struct net_device *ndev)
		rc = wil_up(wil);
		if (rc)
			wil_pm_runtime_put(wil);
	}

	return rc;
}
@@ -46,13 +74,16 @@ static int wil_open(struct net_device *ndev)
static int wil_stop(struct net_device *ndev)
{
	struct wil6210_priv *wil = ndev_to_wil(ndev);
	int rc;
	int rc = 0;

	wil_dbg_misc(wil, "stop\n");

	if (!wil_has_other_up_ifaces(wil, ndev)) {
		wil_dbg_misc(wil, "stop, last iface\n");
		rc = wil_down(wil);
		if (!rc)
			wil_pm_runtime_put(wil);
	}

	return rc;
}
@@ -201,14 +232,32 @@ static void wil_vif_init(struct wil6210_vif *vif)
	INIT_LIST_HEAD(&vif->probe_client_pending);
}

static u8 wil_vif_find_free_mid(struct wil6210_priv *wil)
{
	u8 i;

	for (i = 0; i < wil->max_vifs; i++) {
		if (!wil->vifs[i])
			return i;
	}

	return U8_MAX;
}

struct wil6210_vif *
wil_vif_alloc(struct wil6210_priv *wil, const char *name,
	      unsigned char name_assign_type, enum nl80211_iftype iftype,
	      u8 mid)
	      unsigned char name_assign_type, enum nl80211_iftype iftype)
{
	struct net_device *ndev;
	struct wireless_dev *wdev;
	struct wil6210_vif *vif;
	u8 mid;

	mid = wil_vif_find_free_mid(wil);
	if (mid == U8_MAX) {
		wil_err(wil, "no available virtual interface\n");
		return ERR_PTR(-EINVAL);
	}

	ndev = alloc_netdev(sizeof(*vif), name, name_assign_type,
			    wil_dev_setup);
@@ -216,8 +265,13 @@ wil_vif_alloc(struct wil6210_priv *wil, const char *name,
		dev_err(wil_to_dev(wil), "alloc_netdev failed\n");
		return ERR_PTR(-ENOMEM);
	}
	if (mid == 0)
	if (mid == 0) {
		wil->main_ndev = ndev;
	} else {
		ndev->priv_destructor = wil_ndev_destructor;
		ndev->needs_free_netdev = true;
	}

	vif = ndev_to_vif(ndev);
	vif->ndev = ndev;
	vif->wil = wil;
@@ -263,7 +317,7 @@ void *wil_if_alloc(struct device *dev)
	wil_dbg_misc(wil, "if_alloc\n");

	vif = wil_vif_alloc(wil, "wlan%d", NET_NAME_UNKNOWN,
			    NL80211_IFTYPE_STATION, 0);
			    NL80211_IFTYPE_STATION);
	if (IS_ERR(vif)) {
		dev_err(dev, "wil_vif_alloc failed\n");
		rc = -ENOMEM;
@@ -301,10 +355,43 @@ void wil_if_free(struct wil6210_priv *wil)
	wil_cfg80211_deinit(wil);
}

int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif)
{
	struct net_device *ndev = vif_to_ndev(vif);
	struct wireless_dev *wdev = vif_to_wdev(vif);
	bool any_active = wil_has_up_ifaces(wil);
	int rc;

	ASSERT_RTNL();

	if (wil->vifs[vif->mid]) {
		dev_err(&ndev->dev, "VIF with mid %d already in use\n",
			vif->mid);
		return -EEXIST;
	}
	if (any_active && vif->mid != 0) {
		rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr,
				       wdev->iftype);
		if (rc)
			return rc;
	}
	rc = register_netdevice(ndev);
	if (rc < 0) {
		dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
		if (any_active && vif->mid != 0)
			wmi_port_delete(wil, vif->mid);
		return rc;
	}

	wil->vifs[vif->mid] = vif;
	return 0;
}

int wil_if_add(struct wil6210_priv *wil)
{
	struct wiphy *wiphy = wil->wiphy;
	struct net_device *ndev = wil->main_ndev;
	struct wil6210_vif *vif = ndev_to_vif(ndev);
	int rc;

	wil_dbg_misc(wil, "entered");
@@ -324,11 +411,11 @@ int wil_if_add(struct wil6210_priv *wil)

	wil_update_net_queues_bh(wil, NULL, true);

	rc = register_netdev(ndev);
	if (rc < 0) {
		dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
	rtnl_lock();
	rc = wil_vif_add(wil, vif);
	rtnl_unlock();
	if (rc < 0)
		goto out_wiphy;
	}

	return 0;

@@ -337,6 +424,40 @@ int wil_if_add(struct wil6210_priv *wil)
	return rc;
}

void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
{
	struct wil6210_vif *vif;
	struct net_device *ndev;
	bool any_active = wil_has_up_ifaces(wil);

	ASSERT_RTNL();
	if (mid >= wil->max_vifs) {
		wil_err(wil, "invalid MID: %d\n", mid);
		return;
	}

	vif = wil->vifs[mid];
	if (!vif) {
		wil_err(wil, "MID %d not registered\n", mid);
		return;
	}

	ndev = vif_to_ndev(vif);
	/* during unregister_netdevice cfg80211_leave may perform operations
	 * such as stop AP, disconnect, so we only clear the VIF afterwards
	 */
	unregister_netdevice(ndev);

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

	wil->vifs[mid] = NULL;
	/* 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
	 * a bit longer so logging macros will work.
	 */
}

void wil_if_remove(struct wil6210_priv *wil)
{
	struct net_device *ndev = wil->main_ndev;
@@ -344,6 +465,8 @@ void wil_if_remove(struct wil6210_priv *wil)

	wil_dbg_misc(wil, "if_remove\n");

	unregister_netdev(ndev);
	rtnl_lock();
	wil_vif_remove(wil, 0);
	rtnl_unlock();
	wiphy_unregister(wdev->wiphy);
}
+32 −7
Original line number Diff line number Diff line
@@ -137,6 +137,20 @@ void wil_enable_irq(struct wil6210_priv *wil)
	enable_irq(wil->pdev->irq);
}

static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
{
	struct wil6210_vif *vif;
	int i;

	for (i = 1; i < wil->max_vifs; i++) {
		vif = wil->vifs[i];
		if (vif) {
			wil_vif_prepare_stop(wil, vif);
			wil_vif_remove(wil, vif->mid);
		}
	}
}

/* Bus ops */
static int wil_if_pcie_enable(struct wil6210_priv *wil)
{
@@ -148,10 +162,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
	 */
	int msi_only = pdev->msi_enabled;
	bool _use_msi = use_msi;
	bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
				 wil->fw_capabilities);

	wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only);
	wil_dbg_misc(wil, "if_pcie_enable\n");

	pci_set_master(pdev);

@@ -172,11 +184,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
	if (rc)
		goto stop_master;

	/* need reset here to obtain MAC or in case of WMI-only FW, full reset
	 * and fw loading takes place
	 */
	/* need reset here to obtain MAC */
	mutex_lock(&wil->mutex);
	rc = wil_reset(wil, wmi_only);
	rc = wil_reset(wil, false);
	mutex_unlock(&wil->mutex);
	if (rc)
		goto release_irq;
@@ -356,6 +366,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		goto bus_disable;
	}

	/* in case of WMI-only FW, perform full reset and FW loading */
	if (test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) {
		wil_dbg_misc(wil, "Loading WMI only FW\n");
		mutex_lock(&wil->mutex);
		rc = wil_reset(wil, true);
		mutex_unlock(&wil->mutex);
		if (rc) {
			wil_err(wil, "failed to load WMI only FW\n");
			goto if_remove;
		}
	}

	if (IS_ENABLED(CONFIG_PM))
		wil->pm_notify.notifier_call = wil6210_pm_notify;

@@ -372,6 +394,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)

	return 0;

if_remove:
	wil_if_remove(wil);
bus_disable:
	wil_if_pcie_disable(wil);
err_iounmap:
@@ -402,6 +426,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
	wil6210_debugfs_remove(wil);
	rtnl_lock();
	wil_p2p_wdev_free(wil);
	wil_remove_all_additional_vifs(wil);
	rtnl_unlock();
	wil_if_remove(wil);
	wil_if_pcie_disable(wil);
+18 −3
Original line number Diff line number Diff line
@@ -50,6 +50,11 @@ extern bool disable_ap_sme;
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */

/* maximum number of virtual interfaces the driver supports
 * (including the main interface)
 */
#define WIL_MAX_VIFS 4

/**
 * extract bits [@b0:@b1] (inclusive) from the value @x
 * it should be @b0 <= @b1, or result is incorrect
@@ -714,11 +719,12 @@ struct wil6210_priv {
	DECLARE_BITMAP(hw_capa, hw_capa_last);
	DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
	DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
	u8 n_mids; /* number of additional MIDs as reported by FW */
	u32 recovery_count; /* num of FW recovery attempts in a short time */
	u32 recovery_state; /* FW recovery state machine */
	unsigned long last_fw_recovery; /* jiffies of last fw recovery */
	wait_queue_head_t wq; /* for all wait_event() use */
	u8 max_vifs; /* maximum number of interfaces, including main */
	struct wil6210_vif *vifs[WIL_MAX_VIFS];
	/* profile */
	struct cfg80211_chan_def monitor_chandef;
	u32 monitor_flags;
@@ -935,11 +941,16 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,

struct wil6210_vif *
wil_vif_alloc(struct wil6210_priv *wil, const char *name,
	      unsigned char name_assign_type, enum nl80211_iftype iftype,
	      u8 mid);
	      unsigned char name_assign_type, enum nl80211_iftype iftype);
void wil_vif_free(struct wil6210_vif *vif);
void *wil_if_alloc(struct device *dev);
bool wil_has_other_up_ifaces(struct wil6210_priv *wil,
			     struct net_device *ndev);
bool wil_has_up_ifaces(struct wil6210_priv *wil);
void wil_if_free(struct wil6210_priv *wil);
int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif);
int wil_if_add(struct wil6210_priv *wil);
void wil_vif_remove(struct wil6210_priv *wil, u8 mid);
void wil_if_remove(struct wil6210_priv *wil);
int wil_priv_init(struct wil6210_priv *wil);
void wil_priv_deinit(struct wil6210_priv *wil);
@@ -998,6 +1009,9 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short);
int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
int wmi_new_sta(struct wil6210_vif *vif, const u8 *mac, u8 aid);
int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
		      const u8 *mac, enum nl80211_iftype iftype);
int wmi_port_delete(struct wil6210_priv *wil, u8 mid);
int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
			 u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
			 __le16 ba_timeout, __le16 ba_seq_ctrl);
@@ -1039,6 +1053,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
int wil_cfg80211_iface_combinations_from_fw(
	struct wil6210_priv *wil,
	const struct wil_fw_record_concurrency *conc);
int wil_vif_prepare_stop(struct wil6210_priv *wil, struct wil6210_vif *vif);

#if defined(CONFIG_WIL6210_DEBUGFS)
int wil6210_debugfs_init(struct wil6210_priv *wil);
Loading