[09/10] staging: wfx: allow to set PTA settings

Message ID 20200526171821.934581-10-Jerome.Pouiller@silabs.com
State New
Headers show
Series
  • [01/10] staging: wfx: drop unused variable
Related show

Commit Message

Jerome Pouiller May 26, 2020, 5:18 p.m.
From: Jérôme Pouiller <jerome.pouiller@silabs.com>

The device allows to do Packet Traffic Arbitration (PTA or also Coex)
with other RF chips.

Currently, there is no API to manage the PTA parameters. This patch
provides a vendor extension to nl80211 to change the PTA parameters.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/staging/wfx/hif_api_general.h | 41 ++++++++++++++++
 drivers/staging/wfx/hif_tx.c          | 46 +++++++++++++++++
 drivers/staging/wfx/hif_tx.h          |  5 ++
 drivers/staging/wfx/nl80211_vendor.c  | 71 +++++++++++++++++++++++++++
 drivers/staging/wfx/nl80211_vendor.h  | 16 ++++++
 drivers/staging/wfx/wfx.h             |  4 ++
 6 files changed, 183 insertions(+)

Patch

diff --git a/drivers/staging/wfx/hif_api_general.h b/drivers/staging/wfx/hif_api_general.h
index c8af3534700ca..eb90164ab87c7 100644
--- a/drivers/staging/wfx/hif_api_general.h
+++ b/drivers/staging/wfx/hif_api_general.h
@@ -369,4 +369,45 @@  struct hif_cnf_prevent_rollback {
 	__le32 status;
 } __packed;
 
+struct hif_req_pta_settings {
+	u8     PtaMode;
+	u8     RequestSignalActiveLevel;
+	u8     PrioritySignalActiveLevel;
+	u8     FreqSignalActiveLevel;
+	u8     GrantSignalActiveLevel;
+	u8     CoexType;
+	u8     DefaultGrantState;
+	u8     SimultaneousRxAccesses;
+	u8     PrioritySamplingTime;
+	u8     TxRxSamplingTime;
+	u8     FreqSamplingTime;
+	u8     GrantValidTime;
+	u8     FemControlTime;
+	u8     FirstSlotTime;
+	__le16 PeriodicTxRxSamplingTime;
+	__le16 CoexQuota;
+	__le16 WlanQuota;
+} __packed;
+
+struct hif_cnf_pta_settings {
+	__le32 status;
+} __packed;
+
+struct hif_req_pta_priority {
+	__le32 priority;
+} __packed;
+
+struct hif_cnf_pta_priority {
+	__le32 status;
+} __packed;
+
+struct hif_req_pta_enable {
+	u8     enable;
+	u8     reserved[3];
+} __packed;
+
+struct hif_cnf_pta_enable {
+	__le32 status;
+} __packed;
+
 #endif
diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c
index 899e1eb71a44b..4cb8fe865e58f 100644
--- a/drivers/staging/wfx/hif_tx.c
+++ b/drivers/staging/wfx/hif_tx.c
@@ -535,6 +535,52 @@  int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
 	return ret;
 }
 
+int hif_pta_settings(struct wfx_dev *wdev,
+		     const struct hif_req_pta_settings *parms)
+{
+	int ret;
+	struct hif_msg *hif;
+	struct hif_req_pta_settings *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+	if (!hif)
+		return -ENOMEM;
+	memcpy(body, parms, sizeof(*body));
+	wfx_fill_header(hif, -1, HIF_REQ_ID_PTA_SETTINGS, sizeof(*body));
+	ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+	kfree(hif);
+	return ret;
+}
+
+int hif_pta_priority(struct wfx_dev *wdev, u32 priority)
+{
+	int ret;
+	struct hif_msg *hif;
+	struct hif_req_pta_priority *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+	if (!hif)
+		return -ENOMEM;
+	body->priority = cpu_to_le32(priority);
+	wfx_fill_header(hif, -1, HIF_REQ_ID_PTA_PRIORITY, sizeof(*body));
+	ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+	kfree(hif);
+	return ret;
+}
+
+int hif_pta_enable(struct wfx_dev *wdev, bool enable)
+{
+	int ret;
+	struct hif_msg *hif;
+	struct hif_req_pta_enable *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+	if (!hif)
+		return -ENOMEM;
+	body->enable = enable;
+	wfx_fill_header(hif, -1, HIF_REQ_ID_PTA_STATE, sizeof(*body));
+	ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+	kfree(hif);
+	return ret;
+}
+
 int hif_burn_prevent_rollback(struct wfx_dev *wdev, u32 magic_word)
 {
 	int ret;
diff --git a/drivers/staging/wfx/hif_tx.h b/drivers/staging/wfx/hif_tx.h
index d29c72d94789a..f7202be4e7fc6 100644
--- a/drivers/staging/wfx/hif_tx.h
+++ b/drivers/staging/wfx/hif_tx.h
@@ -15,6 +15,7 @@  struct ieee80211_bss_conf;
 struct ieee80211_tx_queue_params;
 struct cfg80211_scan_request;
 struct hif_req_add_key;
+struct hif_req_pta_settings;
 struct wfx_dev;
 struct wfx_vif;
 
@@ -57,6 +58,10 @@  int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
 int hif_beacon_transmit(struct wfx_vif *wvif, bool enable);
 int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id);
 int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len);
+int hif_pta_settings(struct wfx_dev *wdev,
+		     const struct hif_req_pta_settings *parms);
+int hif_pta_priority(struct wfx_dev *wdev, u32 priority);
+int hif_pta_enable(struct wfx_dev *wdev, bool enable);
 int hif_burn_prevent_rollback(struct wfx_dev *wdev, u32 magic_word);
 int hif_sl_set_mac_key(struct wfx_dev *wdev,
 		       const u8 *slk_key, int destination);
diff --git a/drivers/staging/wfx/nl80211_vendor.c b/drivers/staging/wfx/nl80211_vendor.c
index 1a9d411718a73..d08072adaf9d6 100644
--- a/drivers/staging/wfx/nl80211_vendor.c
+++ b/drivers/staging/wfx/nl80211_vendor.c
@@ -70,3 +70,74 @@  int wfx_nl_burn_antirollback(struct wiphy *wiphy, struct wireless_dev *widev,
 	return 0;
 }
 
+int wfx_nl_pta_params(struct wiphy *wiphy, struct wireless_dev *widev,
+		      const void *data, int data_len)
+{
+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+	struct wfx_dev *wdev = (struct wfx_dev *)hw->priv;
+	int reply_size = nla_total_size(sizeof(wdev->pta_settings)) +
+			 nla_total_size(sizeof(u8)) +
+			 nla_total_size(sizeof(u32));
+	struct nlattr *tb[WFX_NL80211_ATTR_MAX];
+	bool do_enable = false;
+	struct sk_buff *msg;
+	struct nlattr *nla;
+	int rc;
+
+	rc = nla_parse(tb, WFX_NL80211_ATTR_MAX - 1, data, data_len,
+		       wfx_nl_policy, NULL);
+	if (rc)
+		return rc;
+	nla = tb[WFX_NL80211_ATTR_PTA_ENABLE];
+	if (nla) {
+		do_enable = true;
+		wdev->pta_enable = nla_get_u8(tb[WFX_NL80211_ATTR_PTA_ENABLE]);
+	}
+	if (do_enable && !wdev->pta_enable)
+		rc = hif_pta_enable(wdev, wdev->pta_enable);
+	if (rc)
+		return rc;
+	nla = tb[WFX_NL80211_ATTR_PTA_SETTINGS];
+	if (nla) {
+		// User has to care about endianness of data it send.
+		memcpy(&wdev->pta_settings, nla_data(nla),
+		       sizeof(wdev->pta_settings));
+		rc = hif_pta_settings(wdev, &wdev->pta_settings);
+	}
+	if (rc)
+		return rc;
+	nla = tb[WFX_NL80211_ATTR_PTA_PRIORITY];
+	if (nla) {
+		wdev->pta_priority =
+			nla_get_u32(tb[WFX_NL80211_ATTR_PTA_PRIORITY]);
+		rc = hif_pta_priority(wdev, wdev->pta_priority);
+	}
+	if (rc)
+		return rc;
+	if (do_enable && wdev->pta_enable)
+		rc = hif_pta_enable(wdev, wdev->pta_enable);
+	if (rc)
+		return rc;
+
+	msg = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_size);
+	if (!msg)
+		return -ENOMEM;
+	rc = nla_put(msg, WFX_NL80211_ATTR_PTA_SETTINGS,
+		     sizeof(wdev->pta_settings), &wdev->pta_settings);
+	if (rc)
+		goto error;
+	rc = nla_put_u32(msg, WFX_NL80211_ATTR_PTA_PRIORITY,
+			 wdev->pta_priority);
+	if (rc)
+		goto error;
+	rc = nla_put_u8(msg, WFX_NL80211_ATTR_PTA_ENABLE,
+			wdev->pta_enable ? 1 : 0);
+	if (rc)
+		goto error;
+	return cfg80211_vendor_cmd_reply(msg);
+
+error:
+	kfree_skb(msg);
+	return rc;
+}
+
diff --git a/drivers/staging/wfx/nl80211_vendor.h b/drivers/staging/wfx/nl80211_vendor.h
index 49efe8716a654..0ff3bf73f0ad3 100644
--- a/drivers/staging/wfx/nl80211_vendor.h
+++ b/drivers/staging/wfx/nl80211_vendor.h
@@ -18,21 +18,31 @@  int wfx_nl_ps_timeout(struct wiphy *wiphy, struct wireless_dev *widev,
 		      const void *data, int data_len);
 int wfx_nl_burn_antirollback(struct wiphy *wiphy, struct wireless_dev *widev,
 			     const void *data, int data_len);
+int wfx_nl_pta_params(struct wiphy *wiphy, struct wireless_dev *widev,
+		      const void *data, int data_len);
 
 enum {
 	WFX_NL80211_SUBCMD_PS_TIMEOUT                   = 0x10,
 	WFX_NL80211_SUBCMD_BURN_PREVENT_ROLLBACK        = 0x20,
+	WFX_NL80211_SUBCMD_PTA_PARMS                    = 0x30,
 };
 
 enum {
 	WFX_NL80211_ATTR_PS_TIMEOUT     = 1,
 	WFX_NL80211_ATTR_ROLLBACK_MAGIC = 2,
+	WFX_NL80211_ATTR_PTA_ENABLE     = 3,
+	WFX_NL80211_ATTR_PTA_PRIORITY   = 4,
+	WFX_NL80211_ATTR_PTA_SETTINGS   = 5,
 	WFX_NL80211_ATTR_MAX
 };
 
 static const struct nla_policy wfx_nl_policy[WFX_NL80211_ATTR_MAX] = {
 	[WFX_NL80211_ATTR_PS_TIMEOUT]     = NLA_POLICY_RANGE(NLA_S32, -1, 127),
 	[WFX_NL80211_ATTR_ROLLBACK_MAGIC] = { .type = NLA_U32 },
+	[WFX_NL80211_ATTR_PTA_ENABLE]     = NLA_POLICY_MAX(NLA_U8, 1),
+	[WFX_NL80211_ATTR_PTA_PRIORITY]   = { .type = NLA_U32 },
+	[WFX_NL80211_ATTR_PTA_SETTINGS]   =
+		NLA_POLICY_EXACT_LEN(sizeof(struct hif_req_pta_settings)),
 };
 
 static const struct wiphy_vendor_command wfx_nl80211_vendor_commands[] = {
@@ -49,6 +59,12 @@  static const struct wiphy_vendor_command wfx_nl80211_vendor_commands[] = {
 		.policy = wfx_nl_policy,
 		.doit = wfx_nl_burn_antirollback,
 		.maxattr = WFX_NL80211_ATTR_MAX - 1,
+	}, {
+		.info.vendor_id = WFX_NL80211_ID,
+		.info.subcmd = WFX_NL80211_SUBCMD_PTA_PARMS,
+		.policy = wfx_nl_policy,
+		.doit = wfx_nl_pta_params,
+		.maxattr = WFX_NL80211_ATTR_MAX - 1,
 	},
 };
 
diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index ef68aa4086e01..078f7885bf2fa 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -60,6 +60,10 @@  struct wfx_dev {
 	struct mutex		rx_stats_lock;
 	struct hif_tx_power_loop_info tx_power_loop_info;
 	struct mutex		tx_power_loop_info_lock;
+
+	bool			pta_enable;
+	u32			pta_priority;
+	struct hif_req_pta_settings pta_settings;
 };
 
 struct wfx_vif {