From: Jérôme Pouiller <jerome.pouil...@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.pouil...@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(+)

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 {
-- 
2.26.2

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to