|
@@ -2414,12 +2414,28 @@ static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg)
|
|
|
+{
|
|
|
+ /* It is not clear that allowing gaps in chainmask
|
|
|
+ * is helpful. Probably it will not do what user
|
|
|
+ * is hoping for, so warn in that case.
|
|
|
+ */
|
|
|
+ if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ath10k_warn(ar, "mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n",
|
|
|
+ dbg, cm);
|
|
|
+}
|
|
|
+
|
|
|
static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
|
|
+ ath10k_check_chain_mask(ar, tx_ant, "tx");
|
|
|
+ ath10k_check_chain_mask(ar, rx_ant, "rx");
|
|
|
+
|
|
|
ar->cfg_tx_chainmask = tx_ant;
|
|
|
ar->cfg_rx_chainmask = rx_ant;
|
|
|
|
|
@@ -2782,6 +2798,17 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static u32 get_nss_from_chainmask(u16 chain_mask)
|
|
|
+{
|
|
|
+ if ((chain_mask & 0x15) == 0x15)
|
|
|
+ return 4;
|
|
|
+ else if ((chain_mask & 0x7) == 0x7)
|
|
|
+ return 3;
|
|
|
+ else if ((chain_mask & 0x3) == 0x3)
|
|
|
+ return 2;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* TODO:
|
|
|
* Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE,
|
|
@@ -2914,6 +2941,20 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
goto err_vdev_delete;
|
|
|
}
|
|
|
|
|
|
+ if (ar->cfg_tx_chainmask) {
|
|
|
+ u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
|
|
|
+
|
|
|
+ vdev_param = ar->wmi.vdev_param->nss;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
|
|
+ nss);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn(ar, "failed to set vdev %i chainmask 0x%x, nss %i: %d\n",
|
|
|
+ arvif->vdev_id, ar->cfg_tx_chainmask, nss,
|
|
|
+ ret);
|
|
|
+ goto err_vdev_delete;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
|
|
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
|
|
|
if (ret) {
|