OSDN Git Service

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 239a336..2f9a459 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 4937d02..319ad72 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)