diff --git a/drivers/net/wireless/ath/wil6210/ftm.c b/drivers/net/wireless/ath/wil6210/ftm.c index bb51fd4ba9b9..58d49043a25b 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.c +++ b/drivers/net/wireless/ath/wil6210/ftm.c @@ -25,6 +25,9 @@ /* initial token to use on non-secure FTM measurement */ #define WIL_TOF_FTM_DEFAULT_INITIAL_TOKEN 2 +/* maximum AOA burst period, limited by FW */ +#define WIL_AOA_MAX_BURST_PERIOD 255 + #define WIL_TOF_FTM_MAX_LCI_LENGTH (240) #define WIL_TOF_FTM_MAX_LCR_LENGTH (240) @@ -53,6 +56,7 @@ nla_policy wil_nl80211_ftm_peer_policy[QCA_ATTR_FTM_PEER_MAX + 1] = { [QCA_ATTR_FTM_PEER_MEAS_FLAGS] = { .type = NLA_U32 }, [QCA_ATTR_FTM_PEER_MEAS_PARAMS] = { .type = NLA_NESTED }, [QCA_ATTR_FTM_PEER_SEC_TOK_ID] = { .type = NLA_U8 }, + [QCA_ATTR_FTM_PEER_AOA_BURST_PERIOD] = { .type = NLA_U16 }, [QCA_ATTR_FTM_PEER_FREQ] = { .type = NLA_U32 }, }; @@ -351,6 +355,7 @@ wil_ftm_cfg80211_start_session(struct wil6210_vif *vif, } cmd->session_id = cpu_to_le32(WIL_FTM_FW_SESSION_ID); + cmd->aoa_type = request->aoa_type; cmd->num_of_dest = cpu_to_le16(request->n_peers); for (i = 0; i < request->n_peers; i++) { ether_addr_copy(cmd->ftm_dest_info[i].dst_mac, @@ -393,6 +398,8 @@ wil_ftm_cfg80211_start_session(struct wil6210_vif *vif, request->peers[i].params.burst_duration; cmd->ftm_dest_info[i].burst_period = cpu_to_le16(request->peers[i].params.burst_period); + cmd->ftm_dest_info[i].num_burst_per_aoa_meas = + request->peers[i].aoa_burst_period; } rc = wmi_send(wil, WMI_TOF_SESSION_START_CMDID, vif->mid, @@ -482,8 +489,8 @@ wil_aoa_cfg80211_start_measurement(struct wil6210_vif *vif, mutex_lock(&vif->ftm.lock); - if (vif->ftm.aoa_started) { - wil_err(wil, "AOA measurement already running\n"); + if (vif->ftm.aoa_started || vif->ftm.session_started) { + wil_err(wil, "AOA or FTM measurement already running\n"); rc = -EAGAIN; goto out; } @@ -525,8 +532,8 @@ void wil_aoa_cfg80211_meas_result(struct wil6210_vif *vif, mutex_lock(&vif->ftm.lock); - if (!vif->ftm.aoa_started) { - wil_info(wil, "AOA not started, not sending result\n"); + if (!vif->ftm.aoa_started && !vif->ftm.session_started) { + wil_info(wil, "AOA/FTM not started, not sending result\n"); goto out; } @@ -681,6 +688,10 @@ void wil_aoa_evt_meas(struct wil6210_vif *vif, int data_len = len - offsetof(struct wmi_aoa_meas_event, meas_data); struct wil_aoa_meas_result *res; + if (data_len < 0) { + wil_err(wil, "AOA event too short (%d)\n", len); + return; + } data_len = min_t(int, le16_to_cpu(evt->length), data_len); res = kmalloc(sizeof(*res) + data_len, GFP_KERNEL); @@ -753,6 +764,7 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, struct nlattr *tb2[QCA_ATTR_FTM_PEER_MAX + 1]; struct nlattr *peer; int rc, n_peers = 0, index = 0, tmp; + u32 aoa_type = 0; if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities)) return -ENOTSUPP; @@ -774,6 +786,14 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, return -EINVAL; } + if (tb[QCA_ATTR_AOA_TYPE]) { + aoa_type = nla_get_u32(tb[QCA_ATTR_AOA_TYPE]); + if (aoa_type >= QCA_ATTR_AOA_TYPE_MAX) { + wil_err(wil, "invalid AOA type: %d\n", aoa_type); + return -EINVAL; + } + } + nla_for_each_nested(peer, tb[QCA_ATTR_FTM_MEAS_PEERS], tmp) n_peers++; @@ -797,6 +817,7 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, request->session_cookie = nla_get_u64(tb[QCA_ATTR_FTM_SESSION_COOKIE]); + request->aoa_type = aoa_type; request->n_peers = n_peers; nla_for_each_nested(peer, tb[QCA_ATTR_FTM_MEAS_PEERS], tmp) { @@ -825,6 +846,18 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev, if (tb2[QCA_ATTR_FTM_PEER_SEC_TOK_ID]) request->peers[index].secure_token_id = nla_get_u8(tb2[QCA_ATTR_FTM_PEER_SEC_TOK_ID]); + if (tb2[QCA_ATTR_FTM_PEER_AOA_BURST_PERIOD]) { + request->peers[index].aoa_burst_period = + nla_get_u16(tb2[QCA_ATTR_FTM_PEER_AOA_BURST_PERIOD]); + if (request->peers[index].aoa_burst_period > + WIL_AOA_MAX_BURST_PERIOD) { + wil_err(wil, "Invalid AOA burst period at index: %d\n", + index); + rc = -EINVAL; + goto out; + } + } + rc = wil_ftm_parse_meas_params(wil, tb2[QCA_ATTR_FTM_PEER_MEAS_PARAMS], diff --git a/drivers/net/wireless/ath/wil6210/ftm.h b/drivers/net/wireless/ath/wil6210/ftm.h index 7b6f219f1eff..ec9a1464a657 100644 --- a/drivers/net/wireless/ath/wil6210/ftm.h +++ b/drivers/net/wireless/ath/wil6210/ftm.h @@ -421,12 +421,14 @@ struct wil_ftm_meas_peer_info { u32 flags; /* enum qca_attr_ftm_peer_meas_flags */ struct wil_ftm_meas_params params; u8 secure_token_id; + u16 aoa_burst_period; /* 0 if no AOA, >0 every bursts */ }; /* session request, passed to wil_ftm_cfg80211_start_session */ struct wil_ftm_session_request { u64 session_cookie; u32 n_peers; + u32 aoa_type; /* enum qca_wlan_vendor_attr_aoa_type */ /* keep last, variable size according to n_peers */ struct wil_ftm_meas_peer_info peers[0]; }; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 7a19fefa5b85..89238bd046e9 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1425,8 +1425,14 @@ static int wil_get_otp_info(struct wil6210_priv *wil) } if (!is_valid_ether_addr(mac)) { - wil_err(wil, "Invalid MAC %pM\n", mac); - return -EINVAL; + u8 dummy_mac[ETH_ALEN] = { + 0x00, 0xde, 0xad, 0x12, 0x34, 0x56, + }; + if (!test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) + get_random_bytes(dummy_mac + 3, 3); + wil_err(wil, "Invalid MAC %pM, using random %pM\n", mac, + dummy_mac); + ether_addr_copy(mac, dummy_mac); } ether_addr_copy(ndev->perm_addr, mac); @@ -1768,14 +1774,18 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } - if (wil->tt_data_set) - wmi_set_tt_cfg(wil, &wil->tt_data); - wil_collect_fw_info(wil); if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) wil_ps_update(wil, wil->ps_profile); + if (wil->tt_data_set) + wmi_set_tt_cfg(wil, &wil->tt_data); + + if (wil->snr_thresh.enabled) + wmi_set_snr_thresh(wil, wil->snr_thresh.omni, + wil->snr_thresh.direct); + if (wil->platform_ops.notify) { rc = wil->platform_ops.notify(wil->platform_handle, WIL_PLATFORM_EVT_FW_RDY); diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c index cece8ec1ada7..501ee1f1bf5e 100644 --- a/drivers/net/wireless/ath/wil6210/sysfs.c +++ b/drivers/net/wireless/ath/wil6210/sysfs.c @@ -253,10 +253,47 @@ out: static DEVICE_ATTR_RW(fst_link_loss); +static ssize_t +snr_thresh_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + ssize_t len = 0; + + if (wil->snr_thresh.enabled) + len = snprintf(buf, PAGE_SIZE, "omni=%d, direct=%d\n", + wil->snr_thresh.omni, wil->snr_thresh.direct); + + return len; +} + +static ssize_t +snr_thresh_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + int rc; + short omni, direct; + + /* to disable snr threshold, set both omni and direct to 0 */ + if (sscanf(buf, "%hd %hd", &omni, &direct) != 2) + return -EINVAL; + + rc = wmi_set_snr_thresh(wil, omni, direct); + if (!rc) + rc = count; + + return rc; +} + +static DEVICE_ATTR_RW(snr_thresh); + static struct attribute *wil6210_sysfs_entries[] = { &dev_attr_ftm_txrx_offset.attr, &dev_attr_thermal_throttling.attr, &dev_attr_fst_link_loss.attr, + &dev_attr_snr_thresh.attr, NULL }; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 213cb58d3802..fddc8bccc524 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1039,6 +1039,11 @@ struct wil6210_priv { int fw_calib_result; u8 tt_data_set; struct wmi_tt_data tt_data; + struct { + u8 enabled; + short omni; + short direct; + } snr_thresh; struct notifier_block pm_notify; @@ -1440,6 +1445,8 @@ int wmi_link_maintain_cfg_write(struct wil6210_priv *wil, const u8 *addr, bool fst_link_loss); +int wmi_set_snr_thresh(struct wil6210_priv *wil, short omni, short direct); + int wmi_start_sched_scan(struct wil6210_priv *wil, struct cfg80211_sched_scan_request *request); int wmi_stop_sched_scan(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 423d273fc740..51978483f6d5 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -826,7 +826,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) s32 signal; __le16 fc; u32 d_len; - u16 d_status; + s16 snr; if (flen < 0) { wil_err(wil, "MGMT Rx: short event, len %d\n", len); @@ -848,13 +848,13 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) signal = 100 * data->info.rssi; else signal = data->info.sqi; - d_status = le16_to_cpu(data->info.status); + snr = le16_to_cpu(data->info.snr); /* 1/4 dB units */ fc = rx_mgmt_frame->frame_control; wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n", data->info.channel, data->info.mcs, data->info.rssi, data->info.sqi); - wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, + wil_dbg_wmi(wil, "snr %ddB len %d fc 0x%04x\n", snr / 4, d_len, le16_to_cpu(fc)); wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", data->info.qid, data->info.mid, data->info.cid); @@ -888,6 +888,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); + if (wil->snr_thresh.enabled && snr < wil->snr_thresh.omni) { + wil_dbg_wmi(wil, "snr below threshold. dropping\n"); + return; + } + bss = cfg80211_inform_bss_frame_data(wiphy, &bss_data, rx_mgmt_frame, d_len, GFP_KERNEL); @@ -3579,6 +3584,37 @@ out: return rc; } +int wmi_set_snr_thresh(struct wil6210_priv *wil, short omni, short direct) +{ + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); + int rc; + struct wmi_set_connect_snr_thr_cmd cmd = { + .enable = true, + .omni_snr_thr = cpu_to_le16(omni), + .direct_snr_thr = cpu_to_le16(direct), + }; + + if (!test_bit(WMI_FW_CAPABILITY_CONNECT_SNR_THR, wil->fw_capabilities)) + return -ENOTSUPP; + + if (omni == 0 && direct == 0) + cmd.enable = false; + + wil_dbg_wmi(wil, "%s snr thresh omni=%d, direct=%d (1/4 dB units)\n", + cmd.enable ? "enable" : "disable", omni, direct); + + rc = wmi_send(wil, WMI_SET_CONNECT_SNR_THR_CMDID, vif->mid, + &cmd, sizeof(cmd)); + if (rc) + return rc; + + wil->snr_thresh.enabled = cmd.enable; + wil->snr_thresh.omni = omni; + wil->snr_thresh.direct = direct; + + return 0; +} + static void wmi_sched_scan_set_ssids(struct wil6210_priv *wil, struct wmi_start_sched_scan_cmd *cmd, diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index a2f7034489ae..87138708f32b 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2006-2012 Wilocity - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* @@ -97,6 +86,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE = 13, WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14, WMI_FW_CAPABILITY_PNO = 15, + WMI_FW_CAPABILITY_CONNECT_SNR_THR = 16, WMI_FW_CAPABILITY_CHANNEL_BONDING = 17, WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18, WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19, @@ -2436,7 +2426,7 @@ struct wmi_rx_mgmt_info { u8 range; u8 sqi; __le16 stype; - __le16 status; + __le16 snr; __le32 len; /* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */ u8 qid;