[][MAC80211][app][add mt76-vendor muru onoff command]

[Description]
Add mt76-vendor muru_onoff command

[Release-log]
N/A

Usage:
mt76-vendor wlanX set hemu onoff=<val> (bitmap- UL MU-MIMO(bit3), DL MU-MIMO(bit2), UL OFDMA(bit1), DL OFDMA(bit0))

bit  0     1     2     3
   ru_dl ru_ul mu_dl mu_ul

Change-Id: I59c325cfea1d16b1fc110f2965004769642873b5
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6038795
diff --git a/autobuild_mac80211_release/package/kernel/mt76/patches/1008-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch b/autobuild_mac80211_release/package/kernel/mt76/patches/1008-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch
new file mode 100755
index 0000000..18be9d3
--- /dev/null
+++ b/autobuild_mac80211_release/package/kernel/mt76/patches/1008-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch
@@ -0,0 +1,130 @@
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index d547cf6..bec0cd0 100755
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -3871,6 +3871,13 @@ void mt7915_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+ 		if (val == 0)
+ 			dev->dbg.muru_onoff = MUMIMO_DL_CERT | MUMIMO_DL;
+ 		break;
++	case RATE_PARAM_AUTO_HEMU:
++		if (val < 0 || val > 15) {
++			printk("Wrong value! The value is between 0-15.\n");
++			break;
++		}
++		dev->dbg.muru_onoff = val;
++		break;
+ 	}
+ }
+ 
+diff --git a/mt7915/mcu.h b/mt7915/mcu.h
+index af939c4..fc382cd 100644
+--- a/mt7915/mcu.h
++++ b/mt7915/mcu.h
+@@ -431,6 +431,7 @@ enum {
+ #ifdef CONFIG_MTK_VENDOR
+ 	RATE_PARAM_FIXED_MIMO = 30,
+ 	RATE_PARAM_FIXED_OFDMA = 31,
++	RATE_PARAM_AUTO_HEMU = 32,
+ #endif
+ };
+ 
+diff --git a/mt7915/vendor.c b/mt7915/vendor.c
+index 7456c57..cb5b60f 100644
+--- a/mt7915/vendor.c
++++ b/mt7915/vendor.c
+@@ -34,6 +34,11 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
+ 	[MTK_VENDOR_ATTR_WIRELESS_CTRL_CERT] = {.type = NLA_U8 },
+ };
+ 
++static const struct nla_policy
++hemu_ctrl_policy[NUM_MTK_VENDOR_ATTRS_HEMU_CTRL] = {
++	[MTK_VENDOR_ATTR_HEMU_CTRL_ONOFF] = {.type = NLA_U8 },
++};
++
+ static const struct nla_policy
+ rfeature_ctrl_policy[NUM_MTK_VENDOR_ATTRS_RFEATURE_CTRL] = {
+ 	[MTK_VENDOR_ATTR_RFEATURE_CTRL_HE_GI] = {.type = NLA_U8 },
+@@ -942,6 +947,35 @@ static int mt7915_vendor_wireless_ctrl(struct wiphy *wiphy,
+ 	return 0;
+ }
+ 
++static int mt7915_vendor_hemu_ctrl(struct wiphy *wiphy,
++				  struct wireless_dev *wdev,
++				  const void *data,
++				  int data_len)
++{
++	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++	struct mt7915_phy *phy = mt7915_hw_phy(hw);
++	struct mt7915_dev *dev = phy->dev;
++	struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_HEMU_CTRL];
++	int err;
++	u8 val8;
++	u32 val32 = 0;
++
++	err = nla_parse(tb, MTK_VENDOR_ATTR_HEMU_CTRL_MAX, data, data_len,
++			hemu_ctrl_policy, NULL);
++	if (err)
++		return err;
++
++	if (tb[MTK_VENDOR_ATTR_HEMU_CTRL_ONOFF]) {
++		val8 = nla_get_u8(tb[MTK_VENDOR_ATTR_HEMU_CTRL_ONOFF]);
++		val32 |= FIELD_PREP(RATE_CFG_MODE, RATE_PARAM_AUTO_HEMU) |
++			 FIELD_PREP(RATE_CFG_VAL, val8);
++		ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
++			mt7915_set_wireless_vif, &val32);
++	}
++
++	return 0;
++}
++
+ static const struct wiphy_vendor_command mt7915_vendor_commands[] = {
+ 	{
+ 		.info = {
+@@ -988,6 +1022,17 @@ static const struct wiphy_vendor_command mt7915_vendor_commands[] = {
+ 		.doit = mt7915_vendor_wireless_ctrl,
+ 		.policy = wireless_ctrl_policy,
+ 		.maxattr = MTK_VENDOR_ATTR_WIRELESS_CTRL_MAX,
++	},
++	{
++		.info = {
++			.vendor_id = MTK_NL80211_VENDOR_ID,
++			.subcmd = MTK_NL80211_VENDOR_SUBCMD_HEMU_CTRL,
++		},
++		.flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++			WIPHY_VENDOR_CMD_NEED_RUNNING,
++		.doit = mt7915_vendor_hemu_ctrl,
++		.policy = hemu_ctrl_policy,
++		.maxattr = MTK_VENDOR_ATTR_HEMU_CTRL_MAX,
+ 	}
+ };
+ 
+diff --git a/mt7915/vendor.h b/mt7915/vendor.h
+index 1b08321..b5c1420 100644
+--- a/mt7915/vendor.h
++++ b/mt7915/vendor.h
+@@ -8,6 +8,7 @@ enum mtk_nl80211_vendor_subcmds {
+ 	MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL = 0xc2,
+ 	MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL = 0xc3,
+ 	MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL = 0xc4,
++	MTK_NL80211_VENDOR_SUBCMD_HEMU_CTRL = 0xc5,
+ };
+ 
+ enum mtk_capi_control_changed {
+@@ -33,6 +34,17 @@ enum mtk_vendor_attr_wireless_ctrl {
+ 		NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL - 1
+ };
+ 
++enum mtk_vendor_attr_hemu_ctrl {
++	MTK_VENDOR_ATTR_HEMU_CTRL_UNSPEC,
++
++	MTK_VENDOR_ATTR_HEMU_CTRL_ONOFF,
++
++	/* keep last */
++	NUM_MTK_VENDOR_ATTRS_HEMU_CTRL,
++	MTK_VENDOR_ATTR_HEMU_CTRL_MAX =
++		NUM_MTK_VENDOR_ATTRS_HEMU_CTRL - 1
++};
++
+ enum mtk_vendor_attr_rfeature_ctrl {
+ 	MTK_VENDOR_ATTR_RFEATURE_CTRL_UNSPEC,
+ 
diff --git a/feed/mt76-vendor/src/CMakeLists.txt b/feed/mt76-vendor/src/CMakeLists.txt
index db006b7..f5e1d51 100644
--- a/feed/mt76-vendor/src/CMakeLists.txt
+++ b/feed/mt76-vendor/src/CMakeLists.txt
@@ -3,7 +3,7 @@
 PROJECT(mt76-vendor C)
 ADD_DEFINITIONS(-Os -Wall --std=gnu99 -g3)
 
-ADD_EXECUTABLE(mt76-vendor main.c csi.c amnt.c capi.c)
+ADD_EXECUTABLE(mt76-vendor main.c csi.c amnt.c capi.c hemu.c)
 TARGET_LINK_LIBRARIES(mt76-vendor nl-tiny)
 
 SET(CMAKE_INSTALL_PREFIX /usr)
diff --git a/feed/mt76-vendor/src/hemu.c b/feed/mt76-vendor/src/hemu.c
new file mode 100755
index 0000000..ec1cea0
--- /dev/null
+++ b/feed/mt76-vendor/src/hemu.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 2021 Mediatek Inc. */
+#define _GNU_SOURCE
+
+#include "mt76-vendor.h"
+
+static int mt76_hemu_onoff_set_attr(struct nl_msg *msg, int argc, char **argv)
+{
+	char *val;
+
+	val = strchr(argv[0], '=');
+	if (!val)
+		return -EINVAL;
+
+	*(val++) = 0;
+
+	if (!strncmp(argv[0], "onoff", 5))
+		nla_put_u8(msg, MTK_VENDOR_ATTR_HEMU_CTRL_ONOFF, strtoul(val, NULL, 0));
+
+	return 0;
+}
+
+int mt76_hemu_onoff_set(int idx, int argc, char **argv)
+{
+	struct nl_msg *msg;
+	void *data;
+	int ret;
+
+	if (argc < 1)
+		return 1;
+
+	if (unl_genl_init(&unl, "nl80211") < 0) {
+		fprintf(stderr, "Failed to connect to nl80211\n");
+		return 2;
+	}
+
+	msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, false);
+
+	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_HEMU_CTRL))
+		return false;
+
+	data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
+	if (!data)
+		return -ENOMEM;
+
+	mt76_hemu_onoff_set_attr(msg, argc, argv);
+
+	nla_nest_end(msg, data);
+
+	ret = unl_genl_request(&unl, msg, NULL, NULL);
+	if (ret)
+		fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
+
+	unl_free(&unl);
+
+	return ret;
+}
\ No newline at end of file
diff --git a/feed/mt76-vendor/src/main.c b/feed/mt76-vendor/src/main.c
index c95b3f2..64e8b57 100644
--- a/feed/mt76-vendor/src/main.c
+++ b/feed/mt76-vendor/src/main.c
@@ -31,6 +31,8 @@
 		"set ap_wireless ampdu=<enable>",
 		"set ap_wireless amsdu=<enable>",
 		"set ap_wireless cert=<enable>",
+
+		"set hemu onoff=<val> (bitmap- UL MU-MIMO(bit3), DL MU-MIMO(bit2), UL OFDMA(bit1), DL OFDMA(bit0))",
 	};
 	int i;
 
@@ -75,6 +77,8 @@
 			ret = mt76_ap_rfeatures_set(if_idx, argc, argv);
 		else if (!strncmp(subcmd, "ap_wireless", 11))
 			ret = mt76_ap_wireless_set(if_idx, argc, argv);
+		else if (!strncmp(subcmd, "hemu", 4))
+			ret = mt76_hemu_onoff_set(if_idx, argc, argv);
 	} else {
 		usage();
 	}
diff --git a/feed/mt76-vendor/src/mt76-vendor.h b/feed/mt76-vendor/src/mt76-vendor.h
index 7db01d4..c72a0bb 100644
--- a/feed/mt76-vendor/src/mt76-vendor.h
+++ b/feed/mt76-vendor/src/mt76-vendor.h
@@ -38,6 +38,7 @@
 	MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL = 0xc2,
 	MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL = 0xc3,
 	MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL = 0xc4,
+	MTK_NL80211_VENDOR_SUBCMD_HEMU_CTRL = 0xc5,
 };
 
 enum mtk_vendor_attr_csi_ctrl {
@@ -145,6 +146,17 @@
 		NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL - 1
 };
 
+enum mtk_vendor_attr_hemu_ctrl {
+	MTK_VENDOR_ATTR_HEMU_CTRL_UNSPEC,
+
+	MTK_VENDOR_ATTR_HEMU_CTRL_ONOFF,
+
+	/* keep last */
+	NUM_MTK_VENDOR_ATTRS_HEMU_CTRL,
+	MTK_VENDOR_ATTR_HEMU_CTRL_MAX =
+		NUM_MTK_VENDOR_ATTRS_HEMU_CTRL - 1
+};
+
 enum mtk_vendor_attr_rfeature_ctrl {
 	MTK_VENDOR_ATTR_RFEATURE_CTRL_UNSPEC,
 
@@ -197,4 +209,6 @@
 
 int mt76_ap_rfeatures_set(int idx, int argc, char **argv);
 int mt76_ap_wireless_set(int idx, int argc, char **argv);
+
+int mt76_hemu_onoff_set(int idx, int argc, char **argv);
 #endif