Enable UAPSD support for STA mode.

By default mac80211 enable UAPSD for
Voice AC. So, to test this functionality
we need AP with enable UAPSD and run traffic
using VO AC (eg. ping -Q 0xFF). After sending
such ping from AP->STA, HW/FW should not get this
data after AP indicate this in beacon->pvb.
Instead should wait host will send trigger frame
(could be ping STA->AP). For non-UAPSD ACs standard
PS should be used (NULL frames, PSPOLL).

Signed-off-by: Janusz Dziedzic <janusz.dzied...@tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h |    1 +
 drivers/net/wireless/ath/ath10k/mac.c  |   78 ++++++++++++++++++++++++++++----
 2 files changed, 71 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 6c681cf..bef85fb 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -217,6 +217,7 @@ struct ath10k_vif {
        union {
                struct {
                        u8 bssid[ETH_ALEN];
+                       u32 uapsd;
                } sta;
                struct {
                        /* 127 stations; wmi limit */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 110ad3d..c7ee70a 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -963,9 +963,6 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
        }
 }
 
-/*
- * FIXME: Handle STA UAPSD later.
- */
 static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar,
                                        struct ath10k_vif *arvif,
                                        struct ieee80211_sta *sta,
@@ -2318,6 +2315,63 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
        return ret;
 }
 
+static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
+                                u16 ac, bool enable)
+{
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       u32 value = 0;
+       int ret = 0;
+
+       if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+               return 0;
+
+       switch (ac) {
+       case IEEE80211_AC_VO:
+               value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
+                       WMI_STA_PS_UAPSD_AC3_TRIGGER_EN;
+               break;
+       case IEEE80211_AC_VI:
+               value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
+                       WMI_STA_PS_UAPSD_AC2_TRIGGER_EN;
+               break;
+       case IEEE80211_AC_BE:
+               value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
+                       WMI_STA_PS_UAPSD_AC1_TRIGGER_EN;
+               break;
+       case IEEE80211_AC_BK:
+               value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
+                       WMI_STA_PS_UAPSD_AC0_TRIGGER_EN;
+               break;
+       }
+
+       if (enable)
+               arvif->u.sta.uapsd |= value;
+       else
+               arvif->u.sta.uapsd &= ~value;
+
+       ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
+                                         WMI_STA_PS_PARAM_UAPSD,
+                                         arvif->u.sta.uapsd);
+       if (ret) {
+               ath10k_warn("could not set uapsd params %d\n", ret);
+               goto exit;
+       }
+
+       if (arvif->u.sta.uapsd)
+               value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
+       else
+               value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
+
+       ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
+                                         WMI_STA_PS_PARAM_RX_WAKE_POLICY,
+                                         value);
+       if (ret)
+               ath10k_warn("could not set rx wake param %d\n", ret);
+
+exit:
+       return ret;
+}
+
 static int ath10k_conf_tx(struct ieee80211_hw *hw,
                          struct ieee80211_vif *vif, u16 ac,
                          const struct ieee80211_tx_queue_params *params)
@@ -2343,8 +2397,10 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
                break;
        }
 
-       if (WARN_ON(!p))
-               return -EINVAL;
+       if (WARN_ON(!p)) {
+               ret = -EINVAL;
+               goto exit;
+       }
 
        p->cwmin = params->cw_min;
        p->cwmax = params->cw_max;
@@ -2357,13 +2413,18 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
         */
        p->txop = params->txop * 32;
 
-       /* FIXME: can we pass the params->uapsd to the FW? */
        /* FIXME: FW accepts wmm params per hw, not per vif */
-
        ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
+       if (ret) {
+               ath10k_warn("could not set wmm params %d\n", ret);
+               goto exit;
+       }
+
+       ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
        if (ret)
-               ath10k_warn("could not set wmm params (%d)\n", ret);
+               ath10k_warn("could not set sta uapsd %d\n", ret);
 
+exit:
        mutex_unlock(&ar->conf_mutex);
        return ret;
 }
@@ -2864,6 +2925,7 @@ int ath10k_mac_register(struct ath10k *ar)
        ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
                        IEEE80211_HW_SUPPORTS_PS |
                        IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
+                       IEEE80211_HW_SUPPORTS_UAPSD |
                        IEEE80211_HW_MFP_CAPABLE |
                        IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                        IEEE80211_HW_HAS_RATE_CONTROL |
-- 
1.7.9.5

_______________________________________________
ath9k-devel mailing list
ath9k-devel@lists.ath9k.org
https://lists.ath9k.org/mailman/listinfo/ath9k-devel

Reply via email to