summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c1
-rw-r--r--drivers/net/wireless/ath/wil6210/sysfs.c65
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h5
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c55
4 files changed, 126 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 01a27335ec34..9ce3224fcdd3 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -207,6 +207,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++) {
diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c
index a3689738a070..b4c4d09011b4 100644
--- a/drivers/net/wireless/ath/wil6210/sysfs.c
+++ b/drivers/net/wireless/ath/wil6210/sysfs.c
@@ -204,9 +204,74 @@ out:
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 struct attribute *wil6210_sysfs_entries[] = {
&dev_attr_ftm_txrx_offset.attr,
&dev_attr_thermal_throttling.attr,
+ &dev_attr_fst_link_loss.attr,
NULL
};
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index f64323b03a3b..e324fb79dd65 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -532,6 +532,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 {
@@ -980,5 +981,9 @@ 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);
#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 6a6ba02beba0..3f2038863271 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1841,6 +1841,61 @@ void wmi_event_flush(struct wil6210_priv *wil)
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
}
+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)
{