Skip to content

Commit

Permalink
ath11k: Send multiple scan_chan_list messages if required
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Pradeep Kumar Chitrapu authored and Kalle Valo committed Jun 11, 2020
1 parent 194b8ea commit bff621f
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 71 deletions.
161 changes: 90 additions & 71 deletions drivers/net/wireless/ath/ath11k/wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/ath/ath11k/wmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit bff621f

Please sign in to comment.