--- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2162,6 +2162,28 @@ static int ath11k_start_scan(struct ath1 return 0; } +static void ath11k_mac_update_scan_params(struct cfg80211_scan_request *req, + struct scan_req_params *arg) +{ + int i; + struct chan_info *chan = &arg->chan_list.chan[0]; + enum nl80211_band band; + enum nl80211_chan_width width; + + if (req->chandef) { + band = req->chandef->chan->band; + width = req->chandef->width; + } + + arg->chan_list.num_chan = req->n_channels; + for (i = 0; i < arg->chan_list.num_chan; i++) { + if (req->channels) + chan[i].freq = req->channels[i]->center_freq; + if (req->chandef) + chan[i].phymode = ath11k_phymodes[band][width]; + } +} + static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) @@ -2218,10 +2240,16 @@ static int ath11k_mac_op_hw_scan(struct arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE; } - if (req->n_channels) { - arg.num_chan = req->n_channels; - for (i = 0; i < arg.num_chan; i++) - arg.chan_list[i] = req->channels[i]->center_freq; + if (req->n_channels) + ath11k_mac_update_scan_params(req, &arg); + + if (req->chandef) { + arg.scan_f_wide_band = true; + arg.scan_f_passive = true; + arg.chandef = req->chandef; + ret = ath11k_wmi_append_scan_chan_list(ar, &arg); + if (ret) + goto exit; } ret = ath11k_start_scan(ar, &arg); @@ -6302,6 +6330,11 @@ static int __ath11k_mac_register(struct wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); + if (test_bit(WMI_TLV_SERVICE_SCAN_PHYMODE_SUPPORT, + ar->ab->wmi_ab.svc_map)) + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_WIDE_BAND_SCAN); + ar->hw->wiphy->cipher_suites = cipher_suites; ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2004,6 +2004,57 @@ int ath11k_wmi_send_peer_assoc_cmd(struc return ret; } +int ath11k_wmi_append_scan_chan_list(struct ath11k *ar, + struct scan_req_params *arg) +{ + struct scan_chan_list_params *params; + struct channel_param *ch; + struct cfg80211_chan_def *chandef; + struct ieee80211_channel *channel; + int params_len; + int ret; + + params_len = sizeof(struct scan_chan_list_params) + + arg->chan_list.num_chan * sizeof(struct channel_param); + params = kzalloc(params_len, GFP_KERNEL); + + if (!params) + return -ENOMEM; + + params->pdev_id = ar->pdev->pdev_id; + params->nallchans = arg->chan_list.num_chan; + params->append_chan_list = true; + + ch = params->ch_param; + chandef = arg->chandef; + channel = chandef->chan; + + ch->mhz = arg->chan_list.chan[0].freq; + ch->cfreq1 = chandef->center_freq1; + ch->cfreq2 = chandef->center_freq2; + ch->phy_mode = arg->chan_list.chan[0].phymode; + + ch->dfs_set = + !!(channel->flags & IEEE80211_CHAN_RADAR); + ch->is_chan_passive = !!(channel->flags & + IEEE80211_CHAN_NO_IR); + ch->is_chan_passive |= ch->dfs_set; + ch->minpower = 0; + ch->maxpower = channel->max_power * 2; + ch->maxregpower = channel->max_reg_power * 2; + ch->antennamax = channel->max_antenna_gain * 2; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "scan chan list %d freq %d cfreq1 %d phymode %d is_dfs_ch %u is_chan_passive %u\n", + params->nallchans, ch->mhz, ch->cfreq1, ch->phy_mode, + ch->dfs_set, ch->is_chan_passive); + + ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params); + kfree(params); + + return ret; +} + void ath11k_wmi_start_scan_init(struct ath11k *ar, struct scan_req_params *arg) { @@ -2116,13 +2167,15 @@ int ath11k_wmi_send_scan_start_cmd(struc void *ptr; int i, ret, len; u32 *tmp_ptr; + u8 *phy_ptr; u8 extraie_len_with_pad = 0; + u8 phymode_roundup = 0; len = sizeof(*cmd); len += TLV_HDR_SIZE; - if (params->num_chan) - len += params->num_chan * sizeof(u32); + if (params->chan_list.num_chan) + len += params->chan_list.num_chan * sizeof(u32); len += TLV_HDR_SIZE; if (params->num_ssids) @@ -2138,6 +2191,19 @@ int ath11k_wmi_send_scan_start_cmd(struc roundup(params->extraie.len, sizeof(u32)); len += extraie_len_with_pad; + len += TLV_HDR_SIZE; + if (params->scan_f_en_ie_whitelist_in_probe) + len += params->ie_whitelist.num_vendor_oui * + sizeof(struct wmi_vendor_oui); + + len += TLV_HDR_SIZE; + if (params->scan_f_wide_band) + phymode_roundup = + roundup(params->chan_list.num_chan * sizeof(u8), + sizeof(u32)); + + len += phymode_roundup; + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -2167,7 +2233,7 @@ int ath11k_wmi_send_scan_start_cmd(struc cmd->max_scan_time = params->max_scan_time; cmd->probe_delay = params->probe_delay; cmd->burst_duration = params->burst_duration; - cmd->num_chan = params->num_chan; + cmd->num_chan = params->chan_list.num_chan; cmd->num_bssid = params->num_bssid; cmd->num_ssids = params->num_ssids; cmd->ie_len = params->extraie.len; @@ -2175,7 +2241,7 @@ int ath11k_wmi_send_scan_start_cmd(struc ptr += sizeof(*cmd); - len = params->num_chan * sizeof(u32); + len = params->chan_list.num_chan * sizeof(u32); tlv = ptr; tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_UINT32) | @@ -2183,8 +2249,8 @@ int ath11k_wmi_send_scan_start_cmd(struc ptr += TLV_HDR_SIZE; tmp_ptr = (u32 *)ptr; - for (i = 0; i < params->num_chan; ++i) - tmp_ptr[i] = params->chan_list[i]; + for (i = 0; i < params->chan_list.num_chan; ++i) + tmp_ptr[i] = params->chan_list.chan[i].freq; ptr += len; @@ -2225,6 +2291,7 @@ int ath11k_wmi_send_scan_start_cmd(struc ptr += params->num_bssid * sizeof(*bssid); len = extraie_len_with_pad; + tlv = ptr; tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | FIELD_PREP(WMI_TLV_LEN, len); @@ -2236,6 +2303,36 @@ int ath11k_wmi_send_scan_start_cmd(struc ptr += extraie_len_with_pad; + len = params->ie_whitelist.num_vendor_oui * sizeof(struct wmi_vendor_oui); + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | + FIELD_PREP(WMI_TLV_LEN, len); + ptr += TLV_HDR_SIZE; + + if (params->scan_f_en_ie_whitelist_in_probe) { + /* TODO: fill vendor OUIs for probe req ie whitelisting */ + /* currently added for FW TLV validation */ + } + + ptr += cmd->num_vendor_oui * sizeof(struct wmi_vendor_oui); + + len = phymode_roundup; + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | + FIELD_PREP(WMI_TLV_LEN, len); + ptr += TLV_HDR_SIZE; + + /* Wide Band Scan */ + if (params->scan_f_wide_band) { + phy_ptr = ptr; + /* Add PHY mode TLV for wide band scan with phymode + 1 value + * so that phymode '0' is ignored by FW as default value. + */ + for (i = 0; i < params->chan_list.num_chan; ++i) + phy_ptr[i] = params->chan_list.chan[i].phymode + 1; + } + ptr += phymode_roundup; + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID); if (ret) { @@ -2323,6 +2420,9 @@ int ath11k_wmi_send_scan_chan_list_cmd(s cmd->pdev_id = chan_list->pdev_id; cmd->num_scan_chans = chan_list->nallchans; + if (chan_list->append_chan_list) + cmd->flags |= WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG; + ptr = skb->data + sizeof(*cmd); len = sizeof(*chan_info) * chan_list->nallchans; @@ -2375,8 +2475,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(s tchan_info->antennamax); ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI chan scan list chan[%d] = %u\n", - i, chan_info->mhz); + "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n", + i, chan_info->mhz, chan_info->info); ptr += sizeof(*chan_info); --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3009,6 +3009,12 @@ struct wlan_ssid { }; #define WMI_IE_BITMAP_SIZE 8 +#define PROBE_REQ_MAX_OUIS 16 + +struct wmi_vendor_oui { + u32 tlv_header; + u32 oui_type_subtype; /* vendor OUI type and subtype */ +}; #define WMI_SCAN_MAX_NUM_SSID 0x0A /* prefix used by scan requestor ids on the host */ @@ -3130,6 +3136,22 @@ enum { ((flag) |= (((mode) << WMI_SCAN_DWELL_MODE_SHIFT) & \ WMI_SCAN_DWELL_MODE_MASK)) +struct chan_info { + u32 freq; + u32 phymode; +}; + +struct chan_list { + u32 num_chan; + struct chan_info chan[WLAN_SCAN_MAX_NUM_CHANNELS]; +}; + +struct probe_req_whitelist { + u32 ie_bitmap[WMI_IE_BITMAP_SIZE]; + u32 num_vendor_oui; + u32 voui[PROBE_REQ_MAX_OUIS]; +}; + struct scan_req_params { u32 scan_id; u32 scan_req_id; @@ -3190,23 +3212,24 @@ struct scan_req_params { scan_f_forced:1, scan_f_2ghz:1, scan_f_5ghz:1, - scan_f_80mhz:1; + scan_f_wide_band:1; }; u32 scan_flags; }; enum scan_dwelltime_adaptive_mode adaptive_dwell_time_mode; u32 burst_duration; - u32 num_chan; u32 num_bssid; u32 num_ssids; u32 n_probes; - u32 chan_list[WLAN_SCAN_MAX_NUM_CHANNELS]; + struct chan_list chan_list; + struct cfg80211_chan_def *chandef; u32 notify_scan_events; struct wlan_ssid ssid[WLAN_SCAN_MAX_NUM_SSID]; struct wmi_mac_addr bssid_list[WLAN_SCAN_MAX_NUM_BSSID]; struct element_info extraie; struct element_info htcap; struct element_info vhtcap; + struct probe_req_whitelist ie_whitelist; }; struct wmi_ssid_arg { @@ -3555,9 +3578,12 @@ struct wmi_stop_scan_cmd { struct scan_chan_list_params { u32 pdev_id; u16 nallchans; + bool append_chan_list; struct channel_param ch_param[1]; }; +#define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG BIT(0) + struct wmi_scan_chan_list_cmd { u32 tlv_header; u32 num_scan_chans; @@ -5023,6 +5049,8 @@ int ath11k_wmi_vdev_delete(struct ath11k void ath11k_wmi_start_scan_init(struct ath11k *ar, struct scan_req_params *arg); int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, struct scan_req_params *params); +int ath11k_wmi_append_scan_chan_list(struct ath11k *ar, + struct scan_req_params *params); int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar, struct scan_cancel_param *param); int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,