ath11k: Send multiple scan_chan_list messages if required
authorPradeep Kumar Chitrapu <pradeepc@codeaurora.org>
Tue, 9 Jun 2020 06:31:04 +0000 (09:31 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Thu, 11 Jun 2020 05:05:19 +0000 (08:05 +0300)
With addition of 6Ghz channels, it is possible that wmi buffer size can
exceed the maximum wmi buffer size. So iterate over the channel list,
and send multiple messages till channel list is empty.
Also mark PSC channel flag for 6GHz channels accordingly.

Signed-off-by: Pradeep Kumar Chitrapu <pradeepc@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200603001724.12161-8-pradeepc@codeaurora.org
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/ath/ath11k/wmi.h

index 239a336f55f41ed314439c578484663ff5d9653d..2f9a459c423079e49469198ce83f9786be55eace 100644 (file)
@@ -2195,91 +2195,110 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
        struct wmi_tlv *tlv;
        void *ptr;
        int i, ret, len;
+       u16 num_send_chans, num_sends = 0, max_chan_limit = 0;
        u32 *reg1, *reg2;
 
-       len = sizeof(*cmd) + TLV_HDR_SIZE +
-                sizeof(*chan_info) * chan_list->nallchans;
-
-       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
-       if (!skb)
-               return -ENOMEM;
+       tchan_info = &chan_list->ch_param[0];
+       while (chan_list->nallchans) {
+               len = sizeof(*cmd) + TLV_HDR_SIZE;
+               max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) /
+                       sizeof(*chan_info);
 
-       cmd = (struct wmi_scan_chan_list_cmd *)skb->data;
-       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SCAN_CHAN_LIST_CMD) |
-                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+               if (chan_list->nallchans > max_chan_limit)
+                       num_send_chans = max_chan_limit;
+               else
+                       num_send_chans = chan_list->nallchans;
 
-       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
-                  "WMI no.of chan = %d len = %d\n", chan_list->nallchans, len);
-       cmd->pdev_id = chan_list->pdev_id;
-       cmd->num_scan_chans = chan_list->nallchans;
+               chan_list->nallchans -= num_send_chans;
+               len += sizeof(*chan_info) * num_send_chans;
 
-       ptr = skb->data + sizeof(*cmd);
+               skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
+               if (!skb)
+                       return -ENOMEM;
 
-       len = sizeof(*chan_info) * chan_list->nallchans;
-       tlv = ptr;
-       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
-                     FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
-       ptr += TLV_HDR_SIZE;
+               cmd = (struct wmi_scan_chan_list_cmd *)skb->data;
+               cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SCAN_CHAN_LIST_CMD) |
+                       FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+               cmd->pdev_id = chan_list->pdev_id;
+               cmd->num_scan_chans = num_send_chans;
+               if (num_sends)
+                       cmd->flags |= WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG;
 
-       tchan_info = &chan_list->ch_param[0];
+               ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                          "WMI no.of chan = %d len = %d pdev_id = %d num_sends = %d\n",
+                          num_send_chans, len, cmd->pdev_id, num_sends);
 
-       for (i = 0; i < chan_list->nallchans; ++i) {
-               chan_info = ptr;
-               memset(chan_info, 0, sizeof(*chan_info));
-               len = sizeof(*chan_info);
-               chan_info->tlv_header = FIELD_PREP(WMI_TLV_TAG,
-                                                  WMI_TAG_CHANNEL) |
-                                       FIELD_PREP(WMI_TLV_LEN,
-                                                  len - TLV_HDR_SIZE);
-
-               reg1 = &chan_info->reg_info_1;
-               reg2 = &chan_info->reg_info_2;
-               chan_info->mhz = tchan_info->mhz;
-               chan_info->band_center_freq1 = tchan_info->cfreq1;
-               chan_info->band_center_freq2 = tchan_info->cfreq2;
-
-               if (tchan_info->is_chan_passive)
-                       chan_info->info |= WMI_CHAN_INFO_PASSIVE;
-               if (tchan_info->allow_he)
-                       chan_info->info |= WMI_CHAN_INFO_ALLOW_HE;
-               else if (tchan_info->allow_vht)
-                       chan_info->info |= WMI_CHAN_INFO_ALLOW_VHT;
-               else if (tchan_info->allow_ht)
-                       chan_info->info |= WMI_CHAN_INFO_ALLOW_HT;
-               if (tchan_info->half_rate)
-                       chan_info->info |= WMI_CHAN_INFO_HALF_RATE;
-               if (tchan_info->quarter_rate)
-                       chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE;
-
-               chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE,
-                                             tchan_info->phy_mode);
-               *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MIN_PWR,
-                                   tchan_info->minpower);
-               *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_PWR,
-                                   tchan_info->maxpower);
-               *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_REG_PWR,
-                                   tchan_info->maxregpower);
-               *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_REG_CLS,
-                                   tchan_info->reg_class_id);
-               *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX,
-                                   tchan_info->antennamax);
+               ptr = skb->data + sizeof(*cmd);
 
-               ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
-                          "WMI chan scan list chan[%d] = %u\n",
-                          i, chan_info->mhz);
+               len = sizeof(*chan_info) * num_send_chans;
+               tlv = ptr;
+               tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                             FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
+               ptr += TLV_HDR_SIZE;
 
-               ptr += sizeof(*chan_info);
+               for (i = 0; i < num_send_chans; ++i) {
+                       chan_info = ptr;
+                       memset(chan_info, 0, sizeof(*chan_info));
+                       len = sizeof(*chan_info);
+                       chan_info->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                                          WMI_TAG_CHANNEL) |
+                                               FIELD_PREP(WMI_TLV_LEN,
+                                                          len - TLV_HDR_SIZE);
+
+                       reg1 = &chan_info->reg_info_1;
+                       reg2 = &chan_info->reg_info_2;
+                       chan_info->mhz = tchan_info->mhz;
+                       chan_info->band_center_freq1 = tchan_info->cfreq1;
+                       chan_info->band_center_freq2 = tchan_info->cfreq2;
+
+                       if (tchan_info->is_chan_passive)
+                               chan_info->info |= WMI_CHAN_INFO_PASSIVE;
+                       if (tchan_info->allow_he)
+                               chan_info->info |= WMI_CHAN_INFO_ALLOW_HE;
+                       else if (tchan_info->allow_vht)
+                               chan_info->info |= WMI_CHAN_INFO_ALLOW_VHT;
+                       else if (tchan_info->allow_ht)
+                               chan_info->info |= WMI_CHAN_INFO_ALLOW_HT;
+                       if (tchan_info->half_rate)
+                               chan_info->info |= WMI_CHAN_INFO_HALF_RATE;
+                       if (tchan_info->quarter_rate)
+                               chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE;
+                       if (tchan_info->psc_channel)
+                               chan_info->info |= WMI_CHAN_INFO_PSC;
+
+                       chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE,
+                                                     tchan_info->phy_mode);
+                       *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MIN_PWR,
+                                           tchan_info->minpower);
+                       *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_PWR,
+                                           tchan_info->maxpower);
+                       *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_REG_PWR,
+                                           tchan_info->maxregpower);
+                       *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_REG_CLS,
+                                           tchan_info->reg_class_id);
+                       *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX,
+                                           tchan_info->antennamax);
+
+                       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                                  "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n",
+                                  i, chan_info->mhz, chan_info->info);
+
+                       ptr += sizeof(*chan_info);
+
+                       tchan_info++;
+               }
 
-               tchan_info++;
-       }
+               ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SCAN_CHAN_LIST_CMDID);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to send WMI_SCAN_CHAN_LIST cmd\n");
+                       dev_kfree_skb(skb);
+                       return ret;
+               }
 
-       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SCAN_CHAN_LIST_CMDID);
-       if (ret) {
-               ath11k_warn(ar->ab, "failed to send WMI_SCAN_CHAN_LIST cmd\n");
-               dev_kfree_skb(skb);
+               num_sends++;
        }
 
-       return ret;
+       return 0;
 }
 
 int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
index 4937d02839fcb4996925f35430bee77c9d500055..319ad7241e010f175bf45244ca8223a007f597c3 100644 (file)
@@ -54,6 +54,8 @@ struct wmi_tlv {
 #define WLAN_SCAN_PARAMS_MAX_BSSID   4
 #define WLAN_SCAN_PARAMS_MAX_IE_LEN  256
 
+#define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1
+
 #define WMI_BA_MODE_BUFFER_SIZE_256  3
 /*
  * HW mode config type replicated from FW header
@@ -3271,6 +3273,7 @@ struct  wmi_bcn_send_from_host_cmd {
 #define WMI_CHAN_INFO_QUARTER_RATE     BIT(15)
 #define WMI_CHAN_INFO_DFS_FREQ2                BIT(16)
 #define WMI_CHAN_INFO_ALLOW_HE         BIT(17)
+#define WMI_CHAN_INFO_PSC              BIT(18)
 
 #define WMI_CHAN_REG_INFO1_MIN_PWR     GENMASK(7, 0)
 #define WMI_CHAN_REG_INFO1_MAX_PWR     GENMASK(15, 8)