mwifiex: add support for P2P GO in interface type change

When cfg80211 calls to change interface type for P2P GO, send
P2P mode config commands to firmware and set bss role and bss
mode accordingly.

Signed-off-by: Stone Piao <piaoyun@marvell.com>
Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 4990603..94ac40c 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -679,6 +679,9 @@
 {
 	u16 mode = P2P_MODE_DISABLE;
 
+	if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA)
+		mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA);
+
 	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
 				  HostCmd_ACT_GEN_SET, 0, &mode))
 		return -1;
@@ -713,6 +716,35 @@
 }
 
 /*
+ * This function initializes the functionalities for P2P GO.
+ * The P2P GO initialization sequence is:
+ * disable -> device -> GO
+ */
+static int
+mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)
+{
+	u16 mode;
+
+	if (mwifiex_cfg80211_deinit_p2p(priv))
+		return -1;
+
+	mode = P2P_MODE_DEVICE;
+	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
+				  HostCmd_ACT_GEN_SET, 0, &mode))
+		return -1;
+
+	mode = P2P_MODE_GO;
+	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
+				  HostCmd_ACT_GEN_SET, 0, &mode))
+		return -1;
+
+	if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
+		mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_UAP);
+
+	return 0;
+}
+
+/*
  * CFG802.11 operation handler to change interface type.
  */
 static int
@@ -749,6 +781,11 @@
 				return -EFAULT;
 			dev->ieee80211_ptr->iftype = type;
 			return 0;
+		case NL80211_IFTYPE_P2P_GO:
+			if (mwifiex_cfg80211_init_p2p_go(priv))
+				return -EFAULT;
+			dev->ieee80211_ptr->iftype = type;
+			return 0;
 		case NL80211_IFTYPE_UNSPECIFIED:
 			wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
 		case NL80211_IFTYPE_STATION:	/* This shouldn't happen */
@@ -775,6 +812,7 @@
 		}
 		break;
 	case NL80211_IFTYPE_P2P_CLIENT:
+	case NL80211_IFTYPE_P2P_GO:
 		switch (type) {
 		case NL80211_IFTYPE_STATION:
 			if (mwifiex_cfg80211_deinit_p2p(priv))
@@ -1135,7 +1173,7 @@
 {
 	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 
-	if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
+	if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) {
 		wiphy_err(wiphy, "%s: bss_type mismatched\n", __func__);
 		return -EINVAL;
 	}
@@ -1223,7 +1261,7 @@
 	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 	u8 config_bands = 0;
 
-	if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP)
+	if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
 		return -1;
 	if (mwifiex_set_mgmt_ies(priv, &params->beacon))
 		return -1;