From f567650adecb64b77188b52df4f833b65fcdb259 Mon Sep 17 00:00:00 2001 From: Krishna Kumaar Natarajan Date: Mon, 6 Mar 2017 10:28:44 -0800 Subject: [PATCH] qcacld-3.0: [11AX] Add support for vendor commands Add support for vendor commands to query HE capabilities. Add support to include HE capabilities in wma_handle as received from FW to be sent to userspace when queried via vendor sub command. Change-Id: Icbf141bd1e0646346c2b18aabf3dfb3590d853d7 CRs-Fixed: 1073481 --- core/hdd/inc/wlan_hdd_he.h | 60 ++++++++++++++++ core/hdd/src/wlan_hdd_cfg80211.c | 2 + core/hdd/src/wlan_hdd_he.c | 116 +++++++++++++++++++++++++++++++ core/mac/inc/sir_api.h | 15 ++++ core/wma/inc/wma.h | 4 ++ core/wma/inc/wma_he.h | 13 ++++ core/wma/src/wma_he.c | 25 +++++++ 7 files changed, 235 insertions(+) diff --git a/core/hdd/inc/wlan_hdd_he.h b/core/hdd/inc/wlan_hdd_he.h index aa7edf3570d5..9569b4e9a540 100644 --- a/core/hdd/inc/wlan_hdd_he.h +++ b/core/hdd/inc/wlan_hdd_he.h @@ -35,6 +35,40 @@ struct sap_Config; #define HE_CAP_OUI_SIZE 4 #ifdef WLAN_FEATURE_11AX +/** + * enum qca_wlan_vendor_attr_get_he_capabilities - attributes for HE caps. + * vendor command. + * @QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID - invalid + * @QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED - to check if HE capabilities is supported + * @QCA_WLAN_VENDOR_ATTR_PHY_CAPAB - to get HE PHY capabilities + * @QCA_WLAN_VENDOR_ATTR_MAC_CAPAB - to get HE MAC capabilities + * @QCA_WLAN_VENDOR_ATTR_HE_MCS - to get HE MCS + * @QCA_WLAN_VENDOR_ATTR_NUM_SS - to get NUM SS + * @QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK - to get RU index mask + * @QCA_WLAN_VENDOR_ATTR_RU_COUNT - to get RU count, + * @QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD - to get PPE Threshold, + * @QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST - next to last valid enum + * @QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX - max value supported + * + * enum values are used for NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES sub command. + */ +enum qca_wlan_vendor_attr_get_he_capabilities { + QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED, + QCA_WLAN_VENDOR_ATTR_PHY_CAPAB, + QCA_WLAN_VENDOR_ATTR_MAC_CAPAB, + QCA_WLAN_VENDOR_ATTR_HE_MCS, + QCA_WLAN_VENDOR_ATTR_NUM_SS = 5, + QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK, + QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX = + QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST - 1, +}; + void hdd_update_tgt_he_cap(struct hdd_context_s *hdd_ctx, struct wma_tgt_cfg *cfg); void wlan_hdd_check_11ax_support(struct beacon_data_s *beacon, @@ -43,6 +77,28 @@ void hdd_he_print_ini_config(hdd_context_t *hdd_ctx); int hdd_update_he_cap_in_cfg(hdd_context_t *hdd_ctx); void hdd_he_set_sme_config(tSmeConfigParams *sme_config, struct hdd_config *config); + +/** + * wlan_hdd_cfg80211_get_he_cap() - get HE Capabilities + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_get_he_cap(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len); +#define FEATURE_11AX_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_get_he_cap \ +}, + #else static inline void hdd_update_tgt_he_cap(struct hdd_context_s *hdd_ctx, struct wma_tgt_cfg *cfg) @@ -67,5 +123,9 @@ static inline void hdd_he_set_sme_config(tSmeConfigParams *sme_config, struct hdd_config *config) { } + +/* dummy definition */ +#define FEATURE_11AX_VENDOR_COMMANDS + #endif #endif /* if !defined(WLAN_HDD_HE_H)*/ diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 95966722cd0f..ce0d67a35650 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -100,6 +100,7 @@ #include "wlan_hdd_nan_datapath.h" #include "wlan_hdd_disa.h" #include "wlan_hdd_request_manager.h" +#include "wlan_hdd_he.h" #include #include @@ -10074,6 +10075,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { #ifdef WLAN_UMAC_CONVERGENCE COMMON_VENDOR_COMMANDS #endif + FEATURE_11AX_VENDOR_COMMANDS }; #if ((LINUX_VERSION_CODE > KERNEL_VERSION(4, 4, 0)) || \ diff --git a/core/hdd/src/wlan_hdd_he.c b/core/hdd/src/wlan_hdd_he.c index 05b5a21fbffb..36e4bdc0308f 100644 --- a/core/hdd/src/wlan_hdd_he.c +++ b/core/hdd/src/wlan_hdd_he.c @@ -25,6 +25,7 @@ #include "wlan_hdd_main.h" #include "wlan_hdd_he.h" +#include "wma_he.h" /** * hdd_he_wni_cfg_to_string() - return string conversion of HE WNI CFG @@ -336,3 +337,118 @@ void hdd_he_set_sme_config(tSmeConfigParams *sme_config, sme_config->csrConfig.enable_ul_ofdma = config->enable_ul_ofdma; sme_config->csrConfig.enable_ul_mimo = config->enable_ul_mimo; } + +/* + * __wlan_hdd_cfg80211_get_he_cap() - get HE Capabilities + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_get_he_cap(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + QDF_STATUS status; + struct sk_buff *reply_skb; + uint32_t nl_buf_len; + struct he_capability he_cap; + uint8_t he_supported = 0; + + ENTER(); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + nl_buf_len = NLMSG_HDRLEN; + if (sme_is_feature_supported_by_fw(DOT11AX)) { + he_supported = 1; + + status = wma_get_he_capabilities(&he_cap); + if (QDF_STATUS_SUCCESS != status) + return -EINVAL; + } else { + hdd_info("11AX: HE not supported, send only QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED"); + } + + if (he_supported) { + nl_buf_len += NLA_HDRLEN + sizeof(he_supported) + + NLA_HDRLEN + sizeof(he_cap.phy_cap) + + NLA_HDRLEN + sizeof(he_cap.mac_cap) + + NLA_HDRLEN + sizeof(he_cap.mcs) + + NLA_HDRLEN + sizeof(he_cap.ppet.numss_m1) + + NLA_HDRLEN + sizeof(he_cap.ppet.ru_bit_mask) + + NLA_HDRLEN + + sizeof(he_cap.ppet.ppet16_ppet8_ru3_ru0); + } else { + nl_buf_len += NLA_HDRLEN + sizeof(he_supported); + } + + hdd_info("11AX: he_supported: %d", he_supported); + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len); + + if (!reply_skb) { + hdd_err("Allocate reply_skb failed"); + return -EINVAL; + } + + if (nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED, he_supported)) + goto nla_put_failure; + + /* No need to populate other attributes if HE is not supported */ + if (0 == he_supported) + goto end; + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_MAC_CAPAB, he_cap.mac_cap) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_HE_MCS, he_cap.mcs) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_NUM_SS, he_cap.ppet.numss_m1) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK, + he_cap.ppet.ru_bit_mask) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_PHY_CAPAB, + sizeof(u32) * HE_MAX_PHY_CAP_SIZE, he_cap.phy_cap) || + nla_put(reply_skb, QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD, + sizeof(u32) * PSOC_HOST_MAX_NUM_SS, + he_cap.ppet.ppet16_ppet8_ru3_ru0)) + goto nla_put_failure; +end: + ret = cfg80211_vendor_cmd_reply(reply_skb); + EXIT(); + return ret; + +nla_put_failure: + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; +} + +int wlan_hdd_cfg80211_get_he_cap(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_he_cap(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index c62e50be9a4b..d6887d2488ed 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -6919,6 +6919,21 @@ struct wow_enable_params { #define HE_PPET_SIZE 3 #define HE_BYTE_SIZE 8 +#define HE_MAX_PHY_CAP_SIZE 3 + +/** + * struct he_capability - to store 11ax HE capabilities + * @phy_cap: HE PHY capabilities + * @mac_cap: HE MAC capabilities + * @mcs: HE MCS + * @ppet: HE PPE threshold + */ +struct he_capability { + uint32_t phy_cap[HE_MAX_PHY_CAP_SIZE]; + uint32_t mac_cap; + uint32_t mcs; + struct wlan_psoc_host_ppe_threshold ppet; +}; #endif /** diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 5e278399dd70..ec880b67d9fc 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1566,6 +1566,10 @@ typedef struct { tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb; tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb; tSirLLStatsResults *link_stats_results; + +#ifdef WLAN_FEATURE_11AX + struct he_capability he_cap; +#endif } t_wma_handle, *tp_wma_handle; /** diff --git a/core/wma/inc/wma_he.h b/core/wma/inc/wma_he.h index 61e66a47eba1..e2747d3944a1 100644 --- a/core/wma/inc/wma_he.h +++ b/core/wma/inc/wma_he.h @@ -51,6 +51,19 @@ static inline bool wma_is_peer_he_capable(tpAddStaParams params) void wma_update_vdev_he_capable(struct wma_vdev_start_req *req, tpSwitchChannelParams params); +/** + * wma_get_he_capabilities() - Get HE capabilities from WMA + * @he_cap: Pointer to HE capabilities + * + * Currently HE capabilities are not updated in wma_handle. This + * is an interface for upper layer to query capabilities from WMA. + * When the real use case arise, update wma_handle with HE capabilities + * as required. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_get_he_capabilities(struct he_capability *he_cap); + #else static inline void wma_print_he_cap(tDot11fIEvendor_he_cap *he_cap) { diff --git a/core/wma/src/wma_he.c b/core/wma/src/wma_he.c index 3fbbbf472192..324c04a100fd 100644 --- a/core/wma/src/wma_he.c +++ b/core/wma/src/wma_he.c @@ -1096,3 +1096,28 @@ void wma_update_vdev_he_capable(struct wma_vdev_start_req *req, { req->he_capable = params->he_capable; } + +QDF_STATUS wma_get_he_capabilities(struct he_capability *he_cap) +{ + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + WMA_LOGE(FL("Invalid WMA handle")); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(he_cap->phy_cap, + &wma_handle->he_cap.phy_cap, + WMI_MAX_HECAP_PHY_SIZE); + he_cap->mac_cap = wma_handle->he_cap.mac_cap; + he_cap->mcs = wma_handle->he_cap.mcs; + + he_cap->ppet.numss_m1 = wma_handle->he_cap.ppet.numss_m1; + he_cap->ppet.ru_bit_mask = wma_handle->he_cap.ppet.ru_bit_mask; + qdf_mem_copy(&he_cap->ppet.ppet16_ppet8_ru3_ru0, + &wma_handle->he_cap.ppet.ppet16_ppet8_ru3_ru0, + WMI_MAX_NUM_SS); + + return QDF_STATUS_SUCCESS; +}