brcmfmac: support station interface creation version 1, 2 and 3
authorWright Feng <wright.feng@cypress.com>
Thu, 29 Sep 2022 05:06:12 +0000 (00:06 -0500)
committerKalle Valo <kvalo@kernel.org>
Wed, 5 Oct 2022 07:41:45 +0000 (10:41 +0300)
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: Wright Feng <wright.feng@cypress.com>
Signed-off-by: Chi-hsien Lin <chi-hsien.lin@infineon.com>
Signed-off-by: Ian Lin <ian.lin@infineon.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220929050614.31518-3-ian.lin@infineon.com
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c

index 6817e74..e5f0a9e 100644 (file)
@@ -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;