Commit 4388827b authored by Wright Feng's avatar Wright Feng Committed by Kalle Valo
Browse files

brcmfmac: support station interface creation version 1, 2 and 3



To create virtual station interface for RSDB and VSDB, we add interface
creation version 1, 2 and 3 supports
The structures of each version are different and only version 3 and
later version are able to get interface creating version from firmware
side.

The patch has been verified two concurrent stations pings test with
 interface create version 1:
          89342(4359b1)-PCIE: 9.40.100
 interface create version 2:
         4373a0-sdio: 13.10.271
 interface create version 3:
         4373a0-sdio: 13.35.48

Signed-off-by: default avatarWright Feng <wright.feng@cypress.com>
Signed-off-by: default avatarChi-hsien Lin <chi-hsien.lin@infineon.com>
Signed-off-by: default avatarIan Lin <ian.lin@infineon.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220929050614.31518-3-ian.lin@infineon.com
parent 2b5fb30f
Loading
Loading
Loading
Loading
+124 −24
Original line number Diff line number Diff line
@@ -264,17 +264,46 @@ struct parsed_vndr_ies {
	struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
};

#define WL_INTERFACE_CREATE_VER_1		1
#define WL_INTERFACE_CREATE_VER_2		2
#define WL_INTERFACE_CREATE_VER_3		3
#define WL_INTERFACE_CREATE_VER_MAX		WL_INTERFACE_CREATE_VER_3

#define WL_INTERFACE_MAC_DONT_USE	0x0
#define WL_INTERFACE_MAC_USE		0x2

#define WL_INTERFACE_CREATE_STA		0x0
#define WL_INTERFACE_CREATE_AP		0x1

struct wl_interface_create {
	u16	ver;
	u32	flags;
	u8	mac_addr[ETH_ALEN];
	u8	pad[13];
struct wl_interface_create_v1 {
	u16	ver;			/* structure version */
	u32	flags;			/* flags for operation */
	u8	mac_addr[ETH_ALEN];	/* MAC address */
	u32	wlc_index;		/* optional for wlc index */
};

struct wl_interface_create_v2 {
	u16	ver;			/* structure version */
	u8	pad1[2];
	u32	flags;			/* flags for operation */
	u8	mac_addr[ETH_ALEN];	/* MAC address */
	u8	iftype;			/* type of interface created */
	u8	pad2;
	u32	wlc_index;		/* optional for wlc index */
};

struct wl_interface_create_v3 {
	u16 ver;			/* structure version */
	u16 len;			/* length of structure + data */
	u16 fixed_len;			/* length of structure */
	u8 iftype;			/* type of interface created */
	u8 wlc_index;			/* optional for wlc index */
	u32 flags;			/* flags for operation */
	u8 mac_addr[ETH_ALEN];		/* MAC address */
	u8 bssid[ETH_ALEN];		/* optional for BSSID */
	u8 if_index;			/* interface index request */
	u8 pad[3];
	u8 data[];			/* Optional for specific data */
};

static u8 nl80211_band_to_fwil(enum nl80211_band band)
@@ -564,16 +593,14 @@ static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr)
	return -ENOMEM;
}

static void brcmf_set_sta_iface_macaddr(struct brcmf_if *ifp,
					struct wl_interface_create *iface)
static void brcmf_set_vif_sta_macaddr(struct brcmf_if *ifp, u8 *mac_addr)
{
	u8 mac_idx = ifp->drvr->sta_mac_idx;

	/* set difference MAC address with locally administered bit */
	iface->flags |= WL_INTERFACE_MAC_USE;
	memcpy(iface->mac_addr, ifp->mac_addr, ETH_ALEN);
	iface->mac_addr[0] |= 0x02;
	iface->mac_addr[3] ^= mac_idx ? 0xC0 : 0xA0;
	memcpy(mac_addr, ifp->mac_addr, ETH_ALEN);
	mac_addr[0] |= 0x02;
	mac_addr[3] ^= mac_idx ? 0xC0 : 0xA0;
	mac_idx++;
	mac_idx = mac_idx % 2;
	ifp->drvr->sta_mac_idx = mac_idx;
@@ -581,23 +608,96 @@ static void brcmf_set_sta_iface_macaddr(struct brcmf_if *ifp,

static int brcmf_cfg80211_request_sta_if(struct brcmf_if *ifp, u8 *macaddr)
{
	struct wl_interface_create iface;
	struct wl_interface_create_v1 iface_v1;
	struct wl_interface_create_v2 iface_v2;
	struct wl_interface_create_v3 iface_v3;
	u32 iface_create_ver;
	int err;

	memset(&iface, 0, sizeof(iface));
	/* interface_create version 1 */
	memset(&iface_v1, 0, sizeof(iface_v1));
	iface_v1.ver = WL_INTERFACE_CREATE_VER_1;
	iface_v1.flags = WL_INTERFACE_CREATE_STA |
			 WL_INTERFACE_MAC_USE;
	if (!is_zero_ether_addr(macaddr))
		memcpy(iface_v1.mac_addr, macaddr, ETH_ALEN);
	else
		brcmf_set_vif_sta_macaddr(ifp, iface_v1.mac_addr);

	iface.ver = 0;
	iface.flags = WL_INTERFACE_CREATE_STA;
	if (!is_zero_ether_addr(macaddr)) {
		/* set MAC address in cfg80211 params */
		memcpy(iface.mac_addr, macaddr, ETH_ALEN);
	err = brcmf_fil_iovar_data_get(ifp, "interface_create",
				       &iface_v1,
				       sizeof(iface_v1));
	if (err) {
		brcmf_info("failed to create interface(v1), err=%d\n",
			   err);
	} else {
		brcmf_set_sta_iface_macaddr(ifp, &iface);
		brcmf_dbg(INFO, "interface created(v1)\n");
		return 0;
	}

	err = brcmf_fil_iovar_data_get(ifp, "interface_create", &iface,
				       sizeof(iface));
	return err;
	/* interface_create version 2 */
	memset(&iface_v2, 0, sizeof(iface_v2));
	iface_v2.ver = WL_INTERFACE_CREATE_VER_2;
	iface_v2.flags = WL_INTERFACE_MAC_USE;
	iface_v2.iftype = WL_INTERFACE_CREATE_STA;
	if (!is_zero_ether_addr(macaddr))
		memcpy(iface_v2.mac_addr, macaddr, ETH_ALEN);
	else
		brcmf_set_vif_sta_macaddr(ifp, iface_v2.mac_addr);

	err = brcmf_fil_iovar_data_get(ifp, "interface_create",
				       &iface_v2,
				       sizeof(iface_v2));
	if (err) {
		brcmf_info("failed to create interface(v2), err=%d\n",
			   err);
	} else {
		brcmf_dbg(INFO, "interface created(v2)\n");
		return 0;
	}

	/* interface_create version 3+ */
	/* get supported version from firmware side */
	iface_create_ver = 0;
	err = brcmf_fil_bsscfg_int_get(ifp, "interface_create",
				       &iface_create_ver);
	if (err) {
		brcmf_err("fail to get supported version, err=%d\n", err);
		return -EOPNOTSUPP;
	}

	switch (iface_create_ver) {
	case WL_INTERFACE_CREATE_VER_3:
		memset(&iface_v3, 0, sizeof(iface_v3));
		iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
		iface_v3.flags = WL_INTERFACE_MAC_USE;
		iface_v3.iftype = WL_INTERFACE_CREATE_STA;
		if (!is_zero_ether_addr(macaddr))
			memcpy(iface_v3.mac_addr, macaddr, ETH_ALEN);
		else
			brcmf_set_vif_sta_macaddr(ifp, iface_v3.mac_addr);

		err = brcmf_fil_iovar_data_get(ifp, "interface_create",
					       &iface_v3,
					       sizeof(iface_v3));

		if (!err)
			brcmf_dbg(INFO, "interface created(v3)\n");
		break;
	default:
		brcmf_err("not support interface create(v%d)\n",
			  iface_create_ver);
		err = -EOPNOTSUPP;
		break;
	}

	if (err) {
		brcmf_info("station interface creation failed (%d)\n",
			   err);
		return -EIO;
	}

	return 0;
}

static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
@@ -7060,7 +7160,7 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
 *
 * p2p, mchan, and mbss:
 *
 *	#STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
 *	#STA <= 2, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
 *	#STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
 *	#AP <= 4, matching BI, channels = 1, 4 total
 *
@@ -7106,7 +7206,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
		goto err;

	combo[c].num_different_channels = 1 + (rsdb || (p2p && mchan));
	c0_limits[i].max = 1;
	c0_limits[i].max = 1 + (p2p && mchan);
	c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
	if (mon_flag) {
		c0_limits[i].max = 1;