mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge changes Idd374f80,Ife1863b0,I091a6b61,I3962487b,I3f86f231,I4220c551,Ia46fe269,I7afcf86a,I6990cc0e,Ic1084f0b into msm-next
* changes: wil6210: add ioctl interface wil6210: drop RX probe reponses with low SNR wil6210: add sysfs for setting connect SNR threshold wil6210: support AOA in FTM session wil6210: potential buffer overflow in wmi_evt_aoa_meas wil6210: send uevent when creating sysfs files wil6210: add option to ignore OTA regulatory hints wil6210: add sysfs file for enable/disable fst link loss wil6210: add sysfs for thermal throttling configuration wil6210: NOC time-out fixes
This commit is contained in:
commit
8d4be3237f
@ -52,3 +52,14 @@ config WIL6210_DEBUGFS
|
||||
option if you are interested in debugging the driver.
|
||||
|
||||
If unsure, say Y to make it easier to debug problems.
|
||||
|
||||
config WIL6210_WRITE_IOCTL
|
||||
bool "wil6210 write ioctl to the device"
|
||||
depends on WIL6210
|
||||
default y
|
||||
---help---
|
||||
Say Y here to allow write-access from user-space to
|
||||
the device memory through ioctl. This is useful for
|
||||
debugging purposes only.
|
||||
|
||||
If unsure, say N.
|
||||
|
@ -12,6 +12,7 @@ wil6210-y += interrupt.o
|
||||
wil6210-y += txrx.o
|
||||
wil6210-y += debug.o
|
||||
wil6210-y += rx_reorder.o
|
||||
wil6210-y += ioctl.o
|
||||
wil6210-y += fw.o
|
||||
wil6210-y += pm.o
|
||||
wil6210-y += pmc.o
|
||||
|
@ -33,6 +33,10 @@ static struct wiphy_wowlan_support wil_wowlan_support = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static bool ignore_reg_hints = true;
|
||||
module_param(ignore_reg_hints, bool, 0444);
|
||||
MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)");
|
||||
|
||||
#define CHAN60G(_channel, _flags) { \
|
||||
.band = NL80211_BAND_60GHZ, \
|
||||
.center_freq = 56160 + (2160 * (_channel)), \
|
||||
@ -1886,6 +1890,11 @@ static void wil_wiphy_init(struct wiphy *wiphy)
|
||||
wiphy->vendor_events = wil_nl80211_vendor_events;
|
||||
wiphy->n_vendor_events = ARRAY_SIZE(wil_nl80211_vendor_events);
|
||||
|
||||
if (ignore_reg_hints) {
|
||||
wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
|
||||
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
wiphy->wowlan = &wil_wowlan_support;
|
||||
#endif
|
||||
|
@ -38,6 +38,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)
|
||||
|
||||
@ -62,6 +65,7 @@ nla_policy wil_nl80211_ftm_peer_policy[
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS] = { .type = NLA_U32 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS] = { .type = NLA_NESTED },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID] = { .type = NLA_U8 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD] = { .type = NLA_U16 },
|
||||
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
@ -315,8 +319,8 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
|
||||
struct wmi_tof_session_start_cmd *cmd;
|
||||
|
||||
mutex_lock(&wil->ftm.lock);
|
||||
if (wil->ftm.session_started) {
|
||||
wil_err(wil, "FTM session already running\n");
|
||||
if (wil->ftm.session_started || wil->ftm.aoa_started) {
|
||||
wil_err(wil, "FTM or AOA session already running\n");
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
@ -360,6 +364,7 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
|
||||
}
|
||||
|
||||
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,
|
||||
@ -402,6 +407,8 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
|
||||
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, cmd, cmd_len);
|
||||
@ -487,8 +494,8 @@ wil_aoa_cfg80211_start_measurement(struct wil6210_priv *wil,
|
||||
|
||||
mutex_lock(&wil->ftm.lock);
|
||||
|
||||
if (wil->ftm.aoa_started) {
|
||||
wil_err(wil, "AOA measurement already running\n");
|
||||
if (wil->ftm.aoa_started || wil->ftm.session_started) {
|
||||
wil_err(wil, "AOA or FTM measurement already running\n");
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
@ -529,8 +536,8 @@ void wil_aoa_cfg80211_meas_result(struct wil6210_priv *wil,
|
||||
|
||||
mutex_lock(&wil->ftm.lock);
|
||||
|
||||
if (!wil->ftm.aoa_started) {
|
||||
wil_info(wil, "AOA not started, not sending result\n");
|
||||
if (!wil->ftm.aoa_started && !wil->ftm.session_started) {
|
||||
wil_info(wil, "AOA/FTM not started, not sending result\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -683,6 +690,10 @@ void wil_aoa_evt_meas(struct wil6210_priv *wil,
|
||||
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);
|
||||
@ -754,6 +765,7 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct nlattr *tb2[QCA_WLAN_VENDOR_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;
|
||||
@ -775,6 +787,14 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]) {
|
||||
aoa_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]);
|
||||
if (aoa_type >= QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX) {
|
||||
wil_err(wil, "invalid AOA type: %d\n", aoa_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
nla_for_each_nested(peer, tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS],
|
||||
tmp)
|
||||
n_peers++;
|
||||
@ -798,6 +818,7 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
|
||||
request->session_cookie =
|
||||
nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE]);
|
||||
request->aoa_type = aoa_type;
|
||||
request->n_peers = n_peers;
|
||||
nla_for_each_nested(peer, tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS],
|
||||
tmp) {
|
||||
@ -826,6 +847,18 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID])
|
||||
request->peers[index].secure_token_id = nla_get_u8(
|
||||
tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID]);
|
||||
if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD]) {
|
||||
request->peers[index].aoa_burst_period = nla_get_u16(
|
||||
tb2[QCA_WLAN_VENDOR_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_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS],
|
||||
|
@ -437,12 +437,14 @@ struct wil_ftm_meas_peer_info {
|
||||
u32 flags; /* enum qca_wlan_vendor_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 <value> 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];
|
||||
};
|
||||
|
243
drivers/net/wireless/ath/wil6210/ioctl.c
Normal file
243
drivers/net/wireless/ath/wil6210/ioctl.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include <uapi/linux/wil6210_uapi.h>
|
||||
|
||||
#define wil_hex_dump_ioctl(prefix_str, buf, len) \
|
||||
print_hex_dump_debug("DBG[IOC ]" prefix_str, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, buf, len, true)
|
||||
#define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg)
|
||||
|
||||
#define WIL_PRIV_DATA_MAX_LEN 8192
|
||||
#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
|
||||
|
||||
struct wil_android_priv_data {
|
||||
char *buf;
|
||||
int used_len;
|
||||
int total_len;
|
||||
};
|
||||
|
||||
static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, u32 addr,
|
||||
u32 size, enum wil_memio_op op)
|
||||
{
|
||||
void __iomem *a;
|
||||
u32 off;
|
||||
|
||||
switch (op & wil_mmio_addr_mask) {
|
||||
case wil_mmio_addr_linker:
|
||||
a = wmi_buffer(wil, cpu_to_le32(addr));
|
||||
break;
|
||||
case wil_mmio_addr_ahb:
|
||||
a = wmi_addr(wil, addr);
|
||||
break;
|
||||
case wil_mmio_addr_bar:
|
||||
a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF);
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
off = a - wil->csr;
|
||||
if (size >= wil->bar_size - off) {
|
||||
wil_err(wil,
|
||||
"Invalid requested block: off(0x%08x) size(0x%08x)\n",
|
||||
off, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)
|
||||
{
|
||||
struct wil_memio io;
|
||||
void __iomem *a;
|
||||
bool need_copy = false;
|
||||
|
||||
if (copy_from_user(&io, data, sizeof(io)))
|
||||
return -EFAULT;
|
||||
|
||||
wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n",
|
||||
io.addr, io.val, io.op);
|
||||
|
||||
a = wil_ioc_addr(wil, io.addr, sizeof(u32), io.op);
|
||||
if (!a) {
|
||||
wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr,
|
||||
io.op);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* operation */
|
||||
switch (io.op & wil_mmio_op_mask) {
|
||||
case wil_mmio_read:
|
||||
io.val = readl_relaxed(a);
|
||||
need_copy = true;
|
||||
break;
|
||||
#if defined(CONFIG_WIL6210_WRITE_IOCTL)
|
||||
case wil_mmio_write:
|
||||
writel_relaxed(io.val, a);
|
||||
wmb(); /* make sure write propagated to HW */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (need_copy) {
|
||||
wil_dbg_ioctl(wil,
|
||||
"IO done: addr(0x%08x) val(0x%08x) op(0x%08x)\n",
|
||||
io.addr, io.val, io.op);
|
||||
if (copy_to_user(data, &io, sizeof(io)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
|
||||
{
|
||||
struct wil_memio_block io;
|
||||
void *block;
|
||||
void __iomem *a;
|
||||
int rc = 0;
|
||||
|
||||
if (copy_from_user(&io, data, sizeof(io)))
|
||||
return -EFAULT;
|
||||
|
||||
wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n",
|
||||
io.addr, io.size, io.op);
|
||||
|
||||
/* size */
|
||||
if (io.size % 4) {
|
||||
wil_err(wil, "size is not multiple of 4: 0x%08x\n", io.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
a = wil_ioc_addr(wil, io.addr, io.size, io.op);
|
||||
if (!a) {
|
||||
wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr,
|
||||
io.op);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
block = kmalloc(io.size, GFP_USER);
|
||||
if (!block)
|
||||
return -ENOMEM;
|
||||
|
||||
/* operation */
|
||||
switch (io.op & wil_mmio_op_mask) {
|
||||
case wil_mmio_read:
|
||||
wil_memcpy_fromio_32(block, a, io.size);
|
||||
wil_hex_dump_ioctl("Read ", block, io.size);
|
||||
if (copy_to_user(io.block, block, io.size)) {
|
||||
rc = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
break;
|
||||
#if defined(CONFIG_WIL6210_WRITE_IOCTL)
|
||||
case wil_mmio_write:
|
||||
if (copy_from_user(block, io.block, io.size)) {
|
||||
rc = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
wil_memcpy_toio_32(a, block, io.size);
|
||||
wmb(); /* make sure write propagated to HW */
|
||||
wil_hex_dump_ioctl("Write ", block, io.size);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
out_free:
|
||||
kfree(block);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_ioc_android(struct wil6210_priv *wil, void __user *data)
|
||||
{
|
||||
int rc = 0;
|
||||
char *command;
|
||||
struct wil_android_priv_data priv_data;
|
||||
|
||||
wil_dbg_ioctl(wil, "ioc_android\n");
|
||||
|
||||
if (copy_from_user(&priv_data, data, sizeof(priv_data)))
|
||||
return -EFAULT;
|
||||
|
||||
if (priv_data.total_len <= 0 ||
|
||||
priv_data.total_len >= WIL_PRIV_DATA_MAX_LEN) {
|
||||
wil_err(wil, "invalid data len %d\n", priv_data.total_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
command = kmalloc(priv_data.total_len + 1, GFP_KERNEL);
|
||||
if (!command)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(command, priv_data.buf, priv_data.total_len)) {
|
||||
rc = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Make sure the command is NUL-terminated */
|
||||
command[priv_data.total_len] = '\0';
|
||||
|
||||
wil_dbg_ioctl(wil, "ioc_android: command = %s\n", command);
|
||||
|
||||
/* P2P not supported, but WPS is (in AP mode).
|
||||
* Ignore those in order not to block WPS functionality
|
||||
* in non-P2P mode.
|
||||
*/
|
||||
if (strncasecmp(command, CMD_SET_AP_WPS_P2P_IE,
|
||||
strlen(CMD_SET_AP_WPS_P2P_IE)) == 0)
|
||||
rc = 0;
|
||||
else
|
||||
rc = -ENOIOCTLCMD;
|
||||
|
||||
out_free:
|
||||
kfree(command);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (cmd) {
|
||||
case WIL_IOCTL_MEMIO:
|
||||
ret = wil_ioc_memio_dword(wil, data);
|
||||
break;
|
||||
case WIL_IOCTL_MEMIO_BLOCK:
|
||||
ret = wil_ioc_memio_block(wil, data);
|
||||
break;
|
||||
case (SIOCDEVPRIVATE + 1):
|
||||
ret = wil_ioc_android(wil, data);
|
||||
break;
|
||||
default:
|
||||
wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd);
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
wil_dbg_ioctl(wil, "ioctl(0x%04x) -> %d\n", cmd, ret);
|
||||
return ret;
|
||||
}
|
@ -190,6 +190,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
break;
|
||||
}
|
||||
sta->status = wil_sta_unused;
|
||||
sta->fst_link_loss = false;
|
||||
}
|
||||
/* reorder buffers */
|
||||
for (i = 0; i < WIL_STA_TID_NUM; i++) {
|
||||
@ -984,6 +985,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
if (wil->hw_version == HW_VER_UNKNOWN)
|
||||
return -ENODEV;
|
||||
|
||||
wil_dbg_misc(wil, "Prevent DS in BL & mark FW to set T_POWER_ON=0\n");
|
||||
wil_s(wil, RGF_USER_USAGE_8, BIT_USER_PREVENT_DEEP_SLEEP |
|
||||
BIT_USER_SUPPORT_T_POWER_ON_0);
|
||||
|
||||
if (wil->platform_ops.notify) {
|
||||
rc = wil->platform_ops.notify(wil->platform_handle,
|
||||
WIL_PLATFORM_EVT_PRE_RESET);
|
||||
@ -1078,8 +1083,15 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
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);
|
||||
|
||||
wil_collect_fw_info(wil);
|
||||
|
||||
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);
|
||||
|
@ -47,12 +47,20 @@ static int wil_stop(struct net_device *ndev)
|
||||
return wil_down(wil);
|
||||
}
|
||||
|
||||
static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
|
||||
return wil_ioctl(wil, ifr->ifr_data, cmd);
|
||||
}
|
||||
|
||||
static const struct net_device_ops wil_netdev_ops = {
|
||||
.ndo_open = wil_open,
|
||||
.ndo_stop = wil_stop,
|
||||
.ndo_start_xmit = wil_start_xmit,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_do_ioctl = wil_do_ioctl,
|
||||
};
|
||||
|
||||
static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
|
||||
|
@ -94,8 +94,223 @@ static DEVICE_ATTR(ftm_txrx_offset, 0644,
|
||||
wil_ftm_txrx_offset_sysfs_show,
|
||||
wil_ftm_txrx_offset_sysfs_store);
|
||||
|
||||
static ssize_t
|
||||
wil_tt_sysfs_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct wil6210_priv *wil = dev_get_drvdata(dev);
|
||||
ssize_t len;
|
||||
struct wmi_tt_data tt_data;
|
||||
int i, rc;
|
||||
|
||||
rc = wmi_get_tt_cfg(wil, &tt_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
len = snprintf(buf, PAGE_SIZE, " high max critical\n");
|
||||
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "bb: ");
|
||||
if (tt_data.bb_enabled)
|
||||
for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
"%03d-%03d ",
|
||||
tt_data.bb_zones[i].temperature_high,
|
||||
tt_data.bb_zones[i].temperature_low);
|
||||
else
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "* disabled *");
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "\nrf: ");
|
||||
if (tt_data.rf_enabled)
|
||||
for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
"%03d-%03d ",
|
||||
tt_data.rf_zones[i].temperature_high,
|
||||
tt_data.rf_zones[i].temperature_low);
|
||||
else
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "* disabled *");
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
wil_tt_sysfs_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct wil6210_priv *wil = dev_get_drvdata(dev);
|
||||
int i, rc = -EINVAL;
|
||||
char *token, *dupbuf, *tmp;
|
||||
struct wmi_tt_data tt_data = {
|
||||
.bb_enabled = 0,
|
||||
.rf_enabled = 0,
|
||||
};
|
||||
|
||||
tmp = kmemdup(buf, count + 1, GFP_KERNEL);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
tmp[count] = '\0';
|
||||
dupbuf = tmp;
|
||||
|
||||
/* Format for writing is 12 unsigned bytes separated by spaces:
|
||||
* <bb_z1_h> <bb_z1_l> <bb_z2_h> <bb_z2_l> <bb_z3_h> <bb_z3_l> \
|
||||
* <rf_z1_h> <rf_z1_l> <rf_z2_h> <rf_z2_l> <rf_z3_h> <rf_z3_l>
|
||||
* To disable thermal throttling for bb or for rf, use 0 for all
|
||||
* its six set points.
|
||||
*/
|
||||
|
||||
/* bb */
|
||||
for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i) {
|
||||
token = strsep(&dupbuf, " ");
|
||||
if (!token)
|
||||
goto out;
|
||||
if (kstrtou8(token, 0, &tt_data.bb_zones[i].temperature_high))
|
||||
goto out;
|
||||
token = strsep(&dupbuf, " ");
|
||||
if (!token)
|
||||
goto out;
|
||||
if (kstrtou8(token, 0, &tt_data.bb_zones[i].temperature_low))
|
||||
goto out;
|
||||
|
||||
if (tt_data.bb_zones[i].temperature_high > 0 ||
|
||||
tt_data.bb_zones[i].temperature_low > 0)
|
||||
tt_data.bb_enabled = 1;
|
||||
}
|
||||
/* rf */
|
||||
for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i) {
|
||||
token = strsep(&dupbuf, " ");
|
||||
if (!token)
|
||||
goto out;
|
||||
if (kstrtou8(token, 0, &tt_data.rf_zones[i].temperature_high))
|
||||
goto out;
|
||||
token = strsep(&dupbuf, " ");
|
||||
if (!token)
|
||||
goto out;
|
||||
if (kstrtou8(token, 0, &tt_data.rf_zones[i].temperature_low))
|
||||
goto out;
|
||||
|
||||
if (tt_data.rf_zones[i].temperature_high > 0 ||
|
||||
tt_data.rf_zones[i].temperature_low > 0)
|
||||
tt_data.rf_enabled = 1;
|
||||
}
|
||||
|
||||
rc = wmi_set_tt_cfg(wil, &tt_data);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = count;
|
||||
out:
|
||||
kfree(tmp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(thermal_throttling, 0644,
|
||||
wil_tt_sysfs_show, wil_tt_sysfs_store);
|
||||
|
||||
static ssize_t
|
||||
wil_fst_link_loss_sysfs_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct wil6210_priv *wil = dev_get_drvdata(dev);
|
||||
ssize_t len = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++)
|
||||
if (wil->sta[i].status == wil_sta_connected)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
"[%d] %pM %s\n", i, wil->sta[i].addr,
|
||||
wil->sta[i].fst_link_loss ?
|
||||
"On" : "Off");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
wil_fst_link_loss_sysfs_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct wil6210_priv *wil = dev_get_drvdata(dev);
|
||||
u8 addr[ETH_ALEN];
|
||||
char *token, *dupbuf, *tmp;
|
||||
int rc = -EINVAL;
|
||||
bool fst_link_loss;
|
||||
|
||||
tmp = kmemdup(buf, count + 1, GFP_KERNEL);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp[count] = '\0';
|
||||
dupbuf = tmp;
|
||||
|
||||
token = strsep(&dupbuf, " ");
|
||||
if (!token)
|
||||
goto out;
|
||||
|
||||
/* mac address */
|
||||
if (sscanf(token, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&addr[0], &addr[1], &addr[2],
|
||||
&addr[3], &addr[4], &addr[5]) != 6)
|
||||
goto out;
|
||||
|
||||
/* On/Off */
|
||||
if (strtobool(dupbuf, &fst_link_loss))
|
||||
goto out;
|
||||
|
||||
wil_dbg_misc(wil, "set [%pM] with %d\n", addr, fst_link_loss);
|
||||
|
||||
rc = wmi_link_maintain_cfg_write(wil, addr, fst_link_loss);
|
||||
if (!rc)
|
||||
rc = count;
|
||||
|
||||
out:
|
||||
kfree(tmp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(fst_link_loss, 0644,
|
||||
wil_fst_link_loss_sysfs_show,
|
||||
wil_fst_link_loss_sysfs_store);
|
||||
|
||||
static ssize_t
|
||||
wil_snr_thresh_sysfs_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
|
||||
wil_snr_thresh_sysfs_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(snr_thresh, 0644,
|
||||
wil_snr_thresh_sysfs_show,
|
||||
wil_snr_thresh_sysfs_store);
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
@ -115,6 +330,8 @@ int wil6210_sysfs_init(struct wil6210_priv *wil)
|
||||
return err;
|
||||
}
|
||||
|
||||
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -123,4 +340,5 @@ void wil6210_sysfs_remove(struct wil6210_priv *wil)
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
|
||||
sysfs_remove_group(&dev->kobj, &wil6210_attribute_group);
|
||||
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
||||
}
|
||||
|
@ -162,6 +162,9 @@ struct RGF_ICR {
|
||||
#define RGF_USER_USAGE_6 (0x880018)
|
||||
#define BIT_USER_OOB_MODE BIT(31)
|
||||
#define BIT_USER_OOB_R2_MODE BIT(30)
|
||||
#define RGF_USER_USAGE_8 (0x880020)
|
||||
#define BIT_USER_PREVENT_DEEP_SLEEP BIT(0)
|
||||
#define BIT_USER_SUPPORT_T_POWER_ON_0 BIT(1)
|
||||
#define RGF_USER_HW_MACHINE_STATE (0x8801dc)
|
||||
#define HW_MACHINE_BOOT_DONE (0x3fffffd)
|
||||
#define RGF_USER_USER_CPU_0 (0x8801e0)
|
||||
@ -557,6 +560,7 @@ struct wil_sta_info {
|
||||
struct wil_tid_crypto_rx tid_crypto_rx[WIL_STA_TID_NUM];
|
||||
struct wil_tid_crypto_rx group_crypto_rx;
|
||||
u8 aid; /* 1-254; 0 if unknown/not reported */
|
||||
bool fst_link_loss;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -733,6 +737,13 @@ struct wil6210_priv {
|
||||
int fw_calib_result;
|
||||
|
||||
struct wil_ftm_priv ftm;
|
||||
bool tt_data_set;
|
||||
struct wmi_tt_data tt_data;
|
||||
struct {
|
||||
bool enabled;
|
||||
short omni;
|
||||
short direct;
|
||||
} snr_thresh;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -904,6 +915,8 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
|
||||
int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short);
|
||||
int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
|
||||
int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid);
|
||||
int wmi_set_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data);
|
||||
int wmi_get_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data);
|
||||
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
|
||||
u8 dialog_token, __le16 ba_param_set,
|
||||
__le16 ba_timeout, __le16 ba_seq_ctrl);
|
||||
@ -1003,6 +1016,7 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
|
||||
|
||||
int wil_iftype_nl2wmi(enum nl80211_iftype type);
|
||||
|
||||
int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
|
||||
int wil_request_firmware(struct wil6210_priv *wil, const char *name,
|
||||
bool load);
|
||||
bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
|
||||
@ -1037,5 +1051,11 @@ void wil_ftm_evt_per_dest_res(struct wil6210_priv *wil,
|
||||
void wil_aoa_evt_meas(struct wil6210_priv *wil,
|
||||
struct wmi_aoa_meas_event *evt,
|
||||
int len);
|
||||
/* link loss */
|
||||
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);
|
||||
|
||||
#endif /* __WIL6210_H__ */
|
||||
|
@ -369,7 +369,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, 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);
|
||||
@ -391,13 +391,13 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, 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);
|
||||
@ -425,6 +425,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, 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(wiphy, channel, rx_mgmt_frame,
|
||||
d_len, signal, GFP_KERNEL);
|
||||
if (bss) {
|
||||
@ -1816,6 +1821,67 @@ int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_set_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data)
|
||||
{
|
||||
int rc;
|
||||
struct wmi_set_thermal_throttling_cfg_cmd cmd = {
|
||||
.tt_data = *tt_data,
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_set_thermal_throttling_cfg_event evt;
|
||||
} __packed reply;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_THERMAL_THROTTLING,
|
||||
wil->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
rc = wmi_call(wil, WMI_SET_THERMAL_THROTTLING_CFG_CMDID, &cmd,
|
||||
sizeof(cmd), WMI_SET_THERMAL_THROTTLING_CFG_EVENTID,
|
||||
&reply, sizeof(reply), 100);
|
||||
if (rc) {
|
||||
wil_err(wil, "failed to set thermal throttling\n");
|
||||
return rc;
|
||||
}
|
||||
if (reply.evt.status) {
|
||||
wil_err(wil, "set thermal throttling failed, error %d\n",
|
||||
reply.evt.status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
wil->tt_data = *tt_data;
|
||||
wil->tt_data_set = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmi_get_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_get_thermal_throttling_cfg_event evt;
|
||||
} __packed reply;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_THERMAL_THROTTLING,
|
||||
wil->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rc = wmi_call(wil, WMI_GET_THERMAL_THROTTLING_CFG_CMDID, NULL, 0,
|
||||
WMI_GET_THERMAL_THROTTLING_CFG_EVENTID, &reply,
|
||||
sizeof(reply), 100);
|
||||
if (rc) {
|
||||
wil_err(wil, "failed to get thermal throttling\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (tt_data)
|
||||
*tt_data = reply.evt.tt_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wmi_event_flush(struct wil6210_priv *wil)
|
||||
{
|
||||
ulong flags;
|
||||
@ -1912,6 +1978,61 @@ int wmi_resume(struct wil6210_priv *wil)
|
||||
return reply.evt.status;
|
||||
}
|
||||
|
||||
int wmi_link_maintain_cfg_write(struct wil6210_priv *wil,
|
||||
const u8 *addr,
|
||||
bool fst_link_loss)
|
||||
{
|
||||
int rc;
|
||||
int cid = wil_find_cid(wil, addr);
|
||||
u32 cfg_type;
|
||||
struct wmi_link_maintain_cfg_write_cmd cmd;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_link_maintain_cfg_write_done_event evt;
|
||||
} __packed reply;
|
||||
|
||||
if (cid < 0)
|
||||
return cid;
|
||||
|
||||
switch (wil->wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
cfg_type = fst_link_loss ?
|
||||
WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_FST_STA :
|
||||
WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_NORMAL_STA;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
cfg_type = fst_link_loss ?
|
||||
WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_FST_AP :
|
||||
WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_NORMAL_AP;
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "Unsupported for iftype %d", wil->wdev->iftype);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "Setting cid:%d with cfg_type:%d\n", cid, cfg_type);
|
||||
|
||||
cmd.cfg_type = cpu_to_le32(cfg_type);
|
||||
cmd.cid = cpu_to_le32(cid);
|
||||
|
||||
reply.evt.status = cpu_to_le32(WMI_FW_STATUS_FAILURE);
|
||||
|
||||
rc = wmi_call(wil, WMI_LINK_MAINTAIN_CFG_WRITE_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID, &reply,
|
||||
sizeof(reply), 250);
|
||||
if (rc) {
|
||||
wil_err(wil, "Failed to %s FST link loss",
|
||||
fst_link_loss ? "enable" : "disable");
|
||||
} else if (reply.evt.status == WMI_FW_STATUS_SUCCESS) {
|
||||
wil->sta[cid].fst_link_loss = fst_link_loss;
|
||||
} else {
|
||||
wil_err(wil, "WMI_LINK_MAINTAIN_CFG_WRITE_CMDID returned status %d",
|
||||
reply.evt.status);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
|
||||
void *d, int len)
|
||||
{
|
||||
@ -2034,3 +2155,32 @@ out:
|
||||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_set_snr_thresh(struct wil6210_priv *wil, short omni, short direct)
|
||||
{
|
||||
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, &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;
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ enum wmi_fw_capability {
|
||||
WMI_FW_CAPABILITY_RSSI_REPORTING = 12,
|
||||
WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE = 13,
|
||||
WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14,
|
||||
WMI_FW_CAPABILITY_CONNECT_SNR_THR = 16,
|
||||
WMI_FW_CAPABILITY_MAX,
|
||||
};
|
||||
|
||||
@ -1821,7 +1822,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;
|
||||
|
87
include/uapi/linux/wil6210_uapi.h
Normal file
87
include/uapi/linux/wil6210_uapi.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __WIL6210_UAPI_H__
|
||||
#define __WIL6210_UAPI_H__
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
#define __user
|
||||
#endif
|
||||
|
||||
#include <linux/sockios.h>
|
||||
|
||||
/* Numbers SIOCDEVPRIVATE and SIOCDEVPRIVATE + 1
|
||||
* are used by Android devices to implement PNO (preferred network offload).
|
||||
* Albeit it is temporary solution, use different numbers to avoid conflicts
|
||||
*/
|
||||
|
||||
/**
|
||||
* Perform 32-bit I/O operation to the card memory
|
||||
*
|
||||
* User code should arrange data in memory like this:
|
||||
*
|
||||
* struct wil_memio io;
|
||||
* struct ifreq ifr = {
|
||||
* .ifr_data = &io,
|
||||
* };
|
||||
*/
|
||||
#define WIL_IOCTL_MEMIO (SIOCDEVPRIVATE + 2)
|
||||
|
||||
/**
|
||||
* Perform block I/O operation to the card memory
|
||||
*
|
||||
* User code should arrange data in memory like this:
|
||||
*
|
||||
* void *buf;
|
||||
* struct wil_memio_block io = {
|
||||
* .block = buf,
|
||||
* };
|
||||
* struct ifreq ifr = {
|
||||
* .ifr_data = &io,
|
||||
* };
|
||||
*/
|
||||
#define WIL_IOCTL_MEMIO_BLOCK (SIOCDEVPRIVATE + 3)
|
||||
|
||||
/**
|
||||
* operation to perform
|
||||
*
|
||||
* @wil_mmio_op_mask - bits defining operation,
|
||||
* @wil_mmio_addr_mask - bits defining addressing mode
|
||||
*/
|
||||
enum wil_memio_op {
|
||||
wil_mmio_read = 0,
|
||||
wil_mmio_write = 1,
|
||||
wil_mmio_op_mask = 0xff,
|
||||
wil_mmio_addr_linker = 0 << 8,
|
||||
wil_mmio_addr_ahb = 1 << 8,
|
||||
wil_mmio_addr_bar = 2 << 8,
|
||||
wil_mmio_addr_mask = 0xff00,
|
||||
};
|
||||
|
||||
struct wil_memio {
|
||||
uint32_t op; /* enum wil_memio_op */
|
||||
uint32_t addr; /* should be 32-bit aligned */
|
||||
uint32_t val;
|
||||
};
|
||||
|
||||
struct wil_memio_block {
|
||||
uint32_t op; /* enum wil_memio_op */
|
||||
uint32_t addr; /* should be 32-bit aligned */
|
||||
uint32_t size; /* should be multiple of 4 */
|
||||
void __user *block; /* block address */
|
||||
};
|
||||
|
||||
#endif /* __WIL6210_UAPI_H__ */
|
Loading…
x
Reference in New Issue
Block a user