From: Jérôme Pouiller <jerome.pouiller@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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