|
@@ -6851,6 +6851,8 @@ const struct nla_policy wlan_hdd_wifi_config_policy[
|
|
|
[QCA_WLAN_VENDOR_ATTR_CONFIG_NSS] = {.type = NLA_U8 },
|
|
|
[QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE] = {
|
|
|
.type = NLA_U8 },
|
|
|
+ [QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS] = {.type = NLA_U8 },
|
|
|
+ [QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS] = {.type = NLA_U8 },
|
|
|
|
|
|
};
|
|
|
|
|
@@ -7440,6 +7442,117 @@ static int hdd_config_msdu_aggregation(struct hdd_adapter *adapter,
|
|
|
return qdf_status_to_os_return(status);
|
|
|
}
|
|
|
|
|
|
+static QDF_STATUS
|
|
|
+hdd_populate_vdev_chains(struct wlan_mlme_nss_chains *nss_chains_cfg,
|
|
|
+ uint8_t tx_chains,
|
|
|
+ uint8_t rx_chains,
|
|
|
+ enum nss_chains_band_info band,
|
|
|
+ struct wlan_objmgr_vdev *vdev)
|
|
|
+{
|
|
|
+ struct wlan_mlme_nss_chains *dynamic_cfg;
|
|
|
+
|
|
|
+ nss_chains_cfg->num_rx_chains[band] = rx_chains;
|
|
|
+ nss_chains_cfg->num_tx_chains[band] = tx_chains;
|
|
|
+
|
|
|
+ dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
|
|
|
+ if (!dynamic_cfg) {
|
|
|
+ hdd_err("nss chain dynamic config NULL");
|
|
|
+ return QDF_STATUS_E_FAILURE;
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * If user gives any nss value, then chains will be adjusted based on
|
|
|
+ * nss (in SME func sme_validate_user_nss_chain_params).
|
|
|
+ * If Chains are not suitable as per current NSS then, we need to
|
|
|
+ * return, and the below logic is added for the same.
|
|
|
+ */
|
|
|
+
|
|
|
+ if ((dynamic_cfg->rx_nss[band] > rx_chains) ||
|
|
|
+ (dynamic_cfg->tx_nss[band] > tx_chains)) {
|
|
|
+ hdd_err("Chains less than nss, configure correct nss first.");
|
|
|
+ return QDF_STATUS_E_FAILURE;
|
|
|
+ }
|
|
|
+
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+hdd_set_dynamic_antenna_mode(struct hdd_adapter *adapter,
|
|
|
+ uint8_t num_rx_chains,
|
|
|
+ uint8_t num_tx_chains)
|
|
|
+{
|
|
|
+ enum nss_chains_band_info band;
|
|
|
+ struct wlan_mlme_nss_chains user_cfg;
|
|
|
+ QDF_STATUS status;
|
|
|
+ mac_handle_t mac_handle;
|
|
|
+ struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
|
|
|
+ struct wlan_objmgr_vdev *vdev;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = wlan_hdd_validate_context(hdd_ctx);
|
|
|
+ if (0 != ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ mac_handle = hdd_ctx->mac_handle;
|
|
|
+ if (!mac_handle) {
|
|
|
+ hdd_err("NULL MAC handle");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!hdd_is_vdev_in_conn_state(adapter)) {
|
|
|
+ hdd_debug("Vdev (id %d) not in connected/started state, cannot accept command",
|
|
|
+ adapter->vdev_id);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ vdev = hdd_objmgr_get_vdev(adapter);
|
|
|
+ if (!vdev) {
|
|
|
+ hdd_err("vdev is NULL");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ qdf_mem_zero(&user_cfg, sizeof(user_cfg));
|
|
|
+ for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) {
|
|
|
+ status = hdd_populate_vdev_chains(&user_cfg,
|
|
|
+ num_rx_chains,
|
|
|
+ num_tx_chains, band, vdev);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ hdd_objmgr_put_vdev(vdev);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ hdd_objmgr_put_vdev(vdev);
|
|
|
+
|
|
|
+ status = sme_nss_chains_update(mac_handle,
|
|
|
+ &user_cfg,
|
|
|
+ adapter->vdev_id);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int hdd_config_vdev_chains(struct hdd_adapter *adapter,
|
|
|
+ struct nlattr *tb[])
|
|
|
+{
|
|
|
+ struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
|
|
|
+ uint8_t tx_chains, rx_chains;
|
|
|
+ struct nlattr *tx_attr =
|
|
|
+ tb[QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS];
|
|
|
+ struct nlattr *rx_attr =
|
|
|
+ tb[QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS];
|
|
|
+
|
|
|
+ if (!tx_attr && !rx_attr)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ tx_chains = nla_get_u8(tx_attr);
|
|
|
+ rx_chains = nla_get_u8(rx_attr);
|
|
|
+
|
|
|
+ if (hdd_ctx->dynamic_nss_chains_support)
|
|
|
+ return hdd_set_dynamic_antenna_mode(adapter, rx_chains,
|
|
|
+ tx_chains);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int hdd_config_ant_div_period(struct hdd_adapter *adapter,
|
|
|
struct nlattr *tb[])
|
|
|
{
|
|
@@ -9090,6 +9203,7 @@ static const interdependent_setter_fn interdependent_setters[] = {
|
|
|
wlan_hdd_cfg80211_wifi_set_reorder_timeout,
|
|
|
wlan_hdd_cfg80211_wifi_set_rx_blocksize,
|
|
|
hdd_config_msdu_aggregation,
|
|
|
+ hdd_config_vdev_chains,
|
|
|
};
|
|
|
|
|
|
/**
|