ath10k: enhance swba event handler to adapt different size tim bitmap
authorRaja Mani <rmani@qti.qualcomm.com>
Mon, 22 Jun 2015 14:52:20 +0000 (20:22 +0530)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 2 Jul 2015 05:47:11 +0000 (08:47 +0300)
Due to 512 client support in 10.4 firmware, size of tim ie is going
to be slightly higher than non 10.4 firmware. So, size of tim_bitmap
what is carried in swba event from 10.4 firmware is bit higher.

The only bottle neck to reuse existing swba handler
ath10k_wmi_event_host_swba() for 10.4 is that code designed to deal
with fixed size tim bitmap(ie, tim_info[].tim_bitmap in wmi_swba_ev_arg).
This patch removes such size limitation and makes it more suitable
to handle swba event which has different size tim bitmap.

All existing swba event parsing functions are changed to adapt this
change. Actual support to handle 10.4 swba event is added in next patch.
Only preparation is made in this patch.

Signed-off-by: Raja Mani <rmani@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/wmi-tlv.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h

index 620b37b59784eb135fecb591f502f38b26fd8f85..ced35a1e06750c0ff4641ee3b1ae1900ef69ed18 100644 (file)
@@ -709,6 +709,8 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len,
                                         const void *ptr, void *data)
 {
        struct wmi_tlv_swba_parse *swba = data;
+       struct wmi_tim_info_arg *tim_info_arg;
+       const struct wmi_tim_info *tim_info_ev = ptr;
 
        if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO)
                return -EPROTO;
@@ -716,7 +718,21 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len,
        if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info))
                return -ENOBUFS;
 
-       swba->arg->tim_info[swba->n_tim++] = ptr;
+       if (__le32_to_cpu(tim_info_ev->tim_len) >
+            sizeof(tim_info_ev->tim_bitmap)) {
+               ath10k_warn(ar, "refusing to parse invalid swba structure\n");
+               return -EPROTO;
+       }
+
+       tim_info_arg = &swba->arg->tim_info[swba->n_tim];
+       tim_info_arg->tim_len = tim_info_ev->tim_len;
+       tim_info_arg->tim_mcast = tim_info_ev->tim_mcast;
+       tim_info_arg->tim_bitmap = tim_info_ev->tim_bitmap;
+       tim_info_arg->tim_changed = tim_info_ev->tim_changed;
+       tim_info_arg->tim_num_ps_pending = tim_info_ev->tim_num_ps_pending;
+
+       swba->n_tim++;
+
        return 0;
 }
 
index 271ad2f86d24d7fc60c3798f63e84e4ea918f69e..228c3dd6713a2d5df5acef43333af740de3c4823 100644 (file)
@@ -2874,33 +2874,42 @@ exit:
 static void ath10k_wmi_update_tim(struct ath10k *ar,
                                  struct ath10k_vif *arvif,
                                  struct sk_buff *bcn,
-                                 const struct wmi_tim_info *tim_info)
+                                 const struct wmi_tim_info_arg *tim_info)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data;
        struct ieee80211_tim_ie *tim;
        u8 *ies, *ie;
        u8 ie_len, pvm_len;
        __le32 t;
-       u32 v;
+       u32 v, tim_len;
+
+       /* When FW reports 0 in tim_len, ensure atleast first byte
+        * in tim_bitmap is considered for pvm calculation.
+        */
+       tim_len = tim_info->tim_len ? __le32_to_cpu(tim_info->tim_len) : 1;
 
        /* if next SWBA has no tim_changed the tim_bitmap is garbage.
         * we must copy the bitmap upon change and reuse it later */
        if (__le32_to_cpu(tim_info->tim_changed)) {
                int i;
 
-               BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) !=
-                            sizeof(tim_info->tim_bitmap));
+               if (sizeof(arvif->u.ap.tim_bitmap) < tim_len) {
+                       ath10k_warn(ar, "SWBA TIM field is too big (%u), truncated it to %zu",
+                                   tim_len, sizeof(arvif->u.ap.tim_bitmap));
+                       tim_len = sizeof(arvif->u.ap.tim_bitmap);
+               }
 
-               for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) {
+               for (i = 0; i < tim_len; i++) {
                        t = tim_info->tim_bitmap[i / 4];
                        v = __le32_to_cpu(t);
                        arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF;
                }
 
-               /* FW reports either length 0 or 16
-                * so we calculate this on our own */
+               /* FW reports either length 0 or length based on max supported
+                * station. so we calculate this on our own
+                */
                arvif->u.ap.tim_len = 0;
-               for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++)
+               for (i = 0; i < tim_len; i++)
                        if (arvif->u.ap.tim_bitmap[i])
                                arvif->u.ap.tim_len = i;
 
@@ -2924,7 +2933,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
        pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */
 
        if (pvm_len < arvif->u.ap.tim_len) {
-               int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len;
+               int expand_size = tim_len - pvm_len;
                int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len);
                void *next_ie = ie + 2 + ie_len;
 
@@ -2939,7 +2948,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
                }
        }
 
-       if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) {
+       if (pvm_len > tim_len) {
                ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len);
                return;
        }
@@ -3003,7 +3012,21 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
                if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info)))
                        break;
 
-               arg->tim_info[i] = &ev->bcn_info[i].tim_info;
+               if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) >
+                    sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) {
+                       ath10k_warn(ar, "refusing to parse invalid swba structure\n");
+                       return -EPROTO;
+               }
+
+               arg->tim_info[i].tim_len = ev->bcn_info[i].tim_info.tim_len;
+               arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast;
+               arg->tim_info[i].tim_bitmap =
+                               ev->bcn_info[i].tim_info.tim_bitmap;
+               arg->tim_info[i].tim_changed =
+                               ev->bcn_info[i].tim_info.tim_changed;
+               arg->tim_info[i].tim_num_ps_pending =
+                               ev->bcn_info[i].tim_info.tim_num_ps_pending;
+
                arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info;
                i++;
        }
@@ -3016,7 +3039,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
        struct wmi_swba_ev_arg arg = {};
        u32 map;
        int i = -1;
-       const struct wmi_tim_info *tim_info;
+       const struct wmi_tim_info_arg *tim_info;
        const struct wmi_p2p_noa_info *noa_info;
        struct ath10k_vif *arvif;
        struct sk_buff *bcn;
@@ -3045,7 +3068,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                        break;
                }
 
-               tim_info = arg.tim_info[i];
+               tim_info = &arg.tim_info[i];
                noa_info = arg.noa_info[i];
 
                ath10k_dbg(ar, ATH10K_DBG_MGMT,
@@ -3060,6 +3083,10 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                           __le32_to_cpu(tim_info->tim_bitmap[1]),
                           __le32_to_cpu(tim_info->tim_bitmap[0]));
 
+               /* TODO: Only first 4 word from tim_bitmap is dumped.
+                * Extend debug code to dump full tim_bitmap.
+                */
+
                arvif = ath10k_get_arvif(ar, vdev_id);
                if (arvif == NULL) {
                        ath10k_warn(ar, "no vif for vdev_id %d found\n",
index b1e4932f97f9c551e3f5a34b1a4c550974393da0..7c4a15f1ae77da20ac4d85b8491967a242021a73 100644 (file)
@@ -5160,6 +5160,14 @@ struct wmi_tim_info {
        __le32 tim_num_ps_pending;
 } __packed;
 
+struct wmi_tim_info_arg {
+       __le32 tim_len;
+       __le32 tim_mcast;
+       const __le32 *tim_bitmap;
+       __le32 tim_changed;
+       __le32 tim_num_ps_pending;
+} __packed;
+
 /* Maximum number of NOA Descriptors supported */
 #define WMI_P2P_MAX_NOA_DESCRIPTORS 4
 #define WMI_P2P_OPPPS_ENABLE_BIT       BIT(0)
@@ -5710,7 +5718,7 @@ struct wmi_peer_kick_ev_arg {
 
 struct wmi_swba_ev_arg {
        __le32 vdev_map;
-       const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV];
+       struct wmi_tim_info_arg tim_info[WMI_MAX_AP_VDEV];
        const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV];
 };