summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-05-07 22:03:58 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-07 22:03:58 -0700
commit80f232121b69cc69a31ccb2b38c1665d770b0710 (patch)
tree106263eac4ff03b899df695e00dd11e593e74fe2 /drivers/net/wireless/ath
parent82efe439599439a5e1e225ce5740e6cfb777a7dd (diff)
parenta9e41a529681b38087c91ebc0bb91e12f510ca2d (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Highlights: 1) Support AES128-CCM ciphers in kTLS, from Vakul Garg. 2) Add fib_sync_mem to control the amount of dirty memory we allow to queue up between synchronize RCU calls, from David Ahern. 3) Make flow classifier more lockless, from Vlad Buslov. 4) Add PHY downshift support to aquantia driver, from Heiner Kallweit. 5) Add SKB cache for TCP rx and tx, from Eric Dumazet. This reduces contention on SLAB spinlocks in heavy RPC workloads. 6) Partial GSO offload support in XFRM, from Boris Pismenny. 7) Add fast link down support to ethtool, from Heiner Kallweit. 8) Use siphash for IP ID generator, from Eric Dumazet. 9) Pull nexthops even further out from ipv4/ipv6 routes and FIB entries, from David Ahern. 10) Move skb->xmit_more into a per-cpu variable, from Florian Westphal. 11) Improve eBPF verifier speed and increase maximum program size, from Alexei Starovoitov. 12) Eliminate per-bucket spinlocks in rhashtable, and instead use bit spinlocks. From Neil Brown. 13) Allow tunneling with GUE encap in ipvs, from Jacky Hu. 14) Improve link partner cap detection in generic PHY code, from Heiner Kallweit. 15) Add layer 2 encap support to bpf_skb_adjust_room(), from Alan Maguire. 16) Remove SKB list implementation assumptions in SCTP, your's truly. 17) Various cleanups, optimizations, and simplifications in r8169 driver. From Heiner Kallweit. 18) Add memory accounting on TX and RX path of SCTP, from Xin Long. 19) Switch PHY drivers over to use dynamic featue detection, from Heiner Kallweit. 20) Support flow steering without masking in dpaa2-eth, from Ioana Ciocoi. 21) Implement ndo_get_devlink_port in netdevsim driver, from Jiri Pirko. 22) Increase the strict parsing of current and future netlink attributes, also export such policies to userspace. From Johannes Berg. 23) Allow DSA tag drivers to be modular, from Andrew Lunn. 24) Remove legacy DSA probing support, also from Andrew Lunn. 25) Allow ll_temac driver to be used on non-x86 platforms, from Esben Haabendal. 26) Add a generic tracepoint for TX queue timeouts to ease debugging, from Cong Wang. 27) More indirect call optimizations, from Paolo Abeni" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1763 commits) cxgb4: Fix error path in cxgb4_init_module net: phy: improve pause mode reporting in phy_print_status dt-bindings: net: Fix a typo in the phy-mode list for ethernet bindings net: macb: Change interrupt and napi enable order in open net: ll_temac: Improve error message on error IRQ net/sched: remove block pointer from common offload structure net: ethernet: support of_get_mac_address new ERR_PTR error net: usb: smsc: fix warning reported by kbuild test robot staging: octeon-ethernet: Fix of_get_mac_address ERR_PTR check net: dsa: support of_get_mac_address new ERR_PTR error net: dsa: sja1105: Fix status initialization in sja1105_get_ethtool_stats vrf: sit mtu should not be updated when vrf netdev is the link net: dsa: Fix error cleanup path in dsa_init_module l2tp: Fix possible NULL pointer dereference taprio: add null check on sched_nest to avoid potential null pointer dereference net: mvpp2: cls: fix less than zero check on a u32 variable net_sched: sch_fq: handle non connected flows net_sched: sch_fq: do not assume EDT packets are ordered net: hns3: use devm_kcalloc when allocating desc_cb net: hns3: some cleanup for struct hns3_enet_ring ...
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath10k/testmode.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/testmode.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/testmode.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c39
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c38
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c78
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c10
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c35
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx_edma.c74
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx_edma.h47
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h11
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_crash_dump.c18
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c24
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h91
17 files changed, 352 insertions, 137 deletions
diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c
index 6433ff10d80e..a29cfb9c72c2 100644
--- a/drivers/net/wireless/ath/ath10k/testmode.c
+++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -416,8 +416,8 @@ int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
int ret;
- ret = nla_parse(tb, ATH10K_TM_ATTR_MAX, data, len, ath10k_tm_policy,
- NULL);
+ ret = nla_parse_deprecated(tb, ATH10K_TM_ATTR_MAX, data, len,
+ ath10k_tm_policy, NULL);
if (ret)
return ret;
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c
index d8dcacda9add..f3906dbe5495 100644
--- a/drivers/net/wireless/ath/ath6kl/testmode.c
+++ b/drivers/net/wireless/ath/ath6kl/testmode.c
@@ -74,8 +74,8 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
int err, buf_len;
void *buf;
- err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, ath6kl_tm_policy,
- NULL);
+ err = nla_parse_deprecated(tb, ATH6KL_TM_ATTR_MAX, data, len,
+ ath6kl_tm_policy, NULL);
if (err)
return err;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 98141b699c88..a04d8616fe09 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -642,7 +642,7 @@ static int ath9k_of_init(struct ath_softc *sc)
}
mac = of_get_mac_address(np);
- if (mac)
+ if (!IS_ERR(mac))
ether_addr_copy(common->macaddr, mac);
return 0;
diff --git a/drivers/net/wireless/ath/wcn36xx/testmode.c b/drivers/net/wireless/ath/wcn36xx/testmode.c
index 51a038022c8b..7ae14b4d2d0e 100644
--- a/drivers/net/wireless/ath/wcn36xx/testmode.c
+++ b/drivers/net/wireless/ath/wcn36xx/testmode.c
@@ -132,8 +132,8 @@ int wcn36xx_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
unsigned short attr;
wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "Data:", data, len);
- ret = nla_parse(tb, WCN36XX_TM_ATTR_MAX, data, len,
- wcn36xx_tm_policy, NULL);
+ ret = nla_parse_deprecated(tb, WCN36XX_TM_ATTR_MAX, data, len,
+ wcn36xx_tm_policy, NULL);
if (ret)
return ret;
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index a1e226652b4a..804955d24b30 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -465,7 +465,7 @@ static int wil_cfg80211_validate_add_iface(struct wil6210_priv *wil,
.num_different_channels = 1,
};
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
if (wil->vifs[i]) {
wdev = vif_to_wdev(wil->vifs[i]);
params.iftype_num[wdev->iftype]++;
@@ -486,7 +486,7 @@ static int wil_cfg80211_validate_change_iface(struct wil6210_priv *wil,
};
bool check_combos = false;
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
struct wil6210_vif *vif_pos = wil->vifs[i];
if (vif_pos && vif != vif_pos) {
@@ -1274,7 +1274,12 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
params->wait);
out:
+ /* when the sent packet was not acked by receiver(ACK=0), rc will
+ * be -EAGAIN. In this case this function needs to return success,
+ * the ACK=0 will be reflected in tx_status.
+ */
tx_status = (rc == 0);
+ rc = (rc == -EAGAIN) ? 0 : rc;
cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
tx_status, GFP_KERNEL);
@@ -1806,7 +1811,7 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
int rc, i;
struct wiphy *wiphy = wil_to_wiphy(wil);
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
struct wil6210_vif *vif = wil->vifs[i];
struct net_device *ndev;
struct cfg80211_beacon_data bcon = {};
@@ -2620,8 +2625,8 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
- rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
- wil_rf_sector_policy, NULL);
+ rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data,
+ data_len, wil_rf_sector_policy, NULL);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
return rc;
@@ -2679,13 +2684,13 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
QCA_ATTR_PAD))
goto nla_put_failure;
- nl_cfgs = nla_nest_start(msg, QCA_ATTR_DMG_RF_SECTOR_CFG);
+ nl_cfgs = nla_nest_start_noflag(msg, QCA_ATTR_DMG_RF_SECTOR_CFG);
if (!nl_cfgs)
goto nla_put_failure;
for (i = 0; i < WMI_MAX_RF_MODULES_NUM; i++) {
if (!(rf_modules_vec & BIT(i)))
continue;
- nl_cfg = nla_nest_start(msg, i);
+ nl_cfg = nla_nest_start_noflag(msg, i);
if (!nl_cfg)
goto nla_put_failure;
si = &reply.evt.sectors_info[i];
@@ -2740,8 +2745,8 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
- rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
- wil_rf_sector_policy, NULL);
+ rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data,
+ data_len, wil_rf_sector_policy, NULL);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
return rc;
@@ -2773,9 +2778,11 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
cmd.sector_type = sector_type;
nla_for_each_nested(nl_cfg, tb[QCA_ATTR_DMG_RF_SECTOR_CFG],
tmp) {
- rc = nla_parse_nested(tb2, QCA_ATTR_DMG_RF_SECTOR_CFG_MAX,
- nl_cfg, wil_rf_sector_cfg_policy,
- NULL);
+ rc = nla_parse_nested_deprecated(tb2,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_MAX,
+ nl_cfg,
+ wil_rf_sector_cfg_policy,
+ NULL);
if (rc) {
wil_err(wil, "invalid sector cfg\n");
return -EINVAL;
@@ -2847,8 +2854,8 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
- rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
- wil_rf_sector_policy, NULL);
+ rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data,
+ data_len, wil_rf_sector_policy, NULL);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
return rc;
@@ -2955,8 +2962,8 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
- rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
- wil_rf_sector_policy, NULL);
+ rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data,
+ data_len, wil_rf_sector_policy, NULL);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 7ad4e5328439..df2adff6c33a 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -207,6 +207,8 @@ static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil,
seq_puts(s, "???\n");
}
seq_printf(s, " desc_rdy_pol = %d\n", sring->desc_rdy_pol);
+ seq_printf(s, " invalid_buff_id_cnt = %d\n",
+ sring->invalid_buff_id_cnt);
if (sring->va && (sring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
uint i;
@@ -258,6 +260,11 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
wil_halp_vote(wil);
+ if (wil_mem_access_lock(wil)) {
+ wil_halp_unvote(wil);
+ return;
+ }
+
wil_memcpy_fromio_32(&r, off, sizeof(r));
wil_mbox_ring_le2cpus(&r);
/*
@@ -323,6 +330,7 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
}
out:
seq_puts(s, "}\n");
+ wil_mem_access_unlock(wil);
wil_halp_unvote(wil);
}
@@ -601,6 +609,12 @@ static int memread_show(struct seq_file *s, void *data)
if (ret < 0)
return ret;
+ ret = wil_mem_access_lock(wil);
+ if (ret) {
+ wil_pm_runtime_put(wil);
+ return ret;
+ }
+
a = wmi_buffer(wil, cpu_to_le32(mem_addr));
if (a)
@@ -608,6 +622,7 @@ static int memread_show(struct seq_file *s, void *data)
else
seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
+ wil_mem_access_unlock(wil);
wil_pm_runtime_put(wil);
return 0;
@@ -626,10 +641,6 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
size_t unaligned_bytes, aligned_count, ret;
int rc;
- if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
- test_bit(wil_status_suspended, wil_blob->wil->status))
- return 0;
-
if (pos < 0)
return -EINVAL;
@@ -656,11 +667,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
return rc;
}
+ rc = wil_mem_access_lock(wil);
+ if (rc) {
+ kfree(buf);
+ wil_pm_runtime_put(wil);
+ return rc;
+ }
+
wil_memcpy_fromio_32(buf, (const void __iomem *)
wil_blob->blob.data + aligned_pos, aligned_count);
ret = copy_to_user(user_buf, buf + unaligned_bytes, count);
+ wil_mem_access_unlock(wil);
wil_pm_runtime_put(wil);
kfree(buf);
@@ -1364,7 +1383,7 @@ static int link_show(struct seq_file *s, void *data)
if (p->status != wil_sta_connected)
continue;
- vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
+ vif = (mid < GET_MAX_VIFS(wil)) ? wil->vifs[mid] : NULL;
if (vif) {
rc = wil_cid_fill_sinfo(vif, i, sinfo);
if (rc)
@@ -1562,7 +1581,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
break;
}
mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
- if (mid < wil->max_vifs) {
+ if (mid < GET_MAX_VIFS(wil)) {
struct wil6210_vif *vif = wil->vifs[mid];
if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
@@ -1628,7 +1647,7 @@ static int mids_show(struct seq_file *s, void *data)
int i;
mutex_lock(&wil->vif_mutex);
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i];
if (vif) {
@@ -1849,7 +1868,7 @@ static int wil_link_stats_debugfs_show(struct seq_file *s, void *data)
/* iterate over all MIDs and show per-cid statistics. Then show the
* global statistics
*/
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i];
seq_printf(s, "MID %d ", i);
@@ -1905,7 +1924,7 @@ static ssize_t wil_link_stats_write(struct file *file, const char __user *buf,
if (rc)
return rc;
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i];
if (!vif)
continue;
@@ -2375,6 +2394,7 @@ static const struct dbg_off dbg_wil_regs[] = {
{"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
doff_io32},
{"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
+ {"RGF_USER_USAGE_2", 0444, HOSTADDR(RGF_USER_USAGE_2), doff_io32},
{},
};
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index 388b3d4717ca..3ec0f2fab9b7 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -647,6 +647,8 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
out:
release_firmware(fw);
+ if (rc)
+ wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc);
return rc;
}
@@ -741,6 +743,8 @@ int wil_request_board(struct wil6210_priv *wil, const char *name)
out:
release_firmware(brd);
+ if (rc)
+ wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc);
return rc;
}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 277abfdf3322..9b9c9ec01536 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -184,6 +184,28 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
}
}
+/* Device memory access is prohibited while reset or suspend.
+ * wil_mem_access_lock protects accessing device memory in these cases
+ */
+int wil_mem_access_lock(struct wil6210_priv *wil)
+{
+ if (!down_read_trylock(&wil->mem_lock))
+ return -EBUSY;
+
+ if (test_bit(wil_status_suspending, wil->status) ||
+ test_bit(wil_status_suspended, wil->status)) {
+ up_read(&wil->mem_lock);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+void wil_mem_access_unlock(struct wil6210_priv *wil)
+{
+ up_read(&wil->mem_lock);
+}
+
static void wil_ring_fini_tx(struct wil6210_priv *wil, int id)
{
struct wil_ring *ring = &wil->ring_tx[id];
@@ -663,7 +685,7 @@ void wil_bcast_fini_all(struct wil6210_priv *wil)
int i;
struct wil6210_vif *vif;
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i];
if (vif)
wil_bcast_fini(vif);
@@ -703,6 +725,7 @@ int wil_priv_init(struct wil6210_priv *wil)
spin_lock_init(&wil->wmi_ev_lock);
spin_lock_init(&wil->net_queue_lock);
init_waitqueue_head(&wil->wq);
+ init_rwsem(&wil->mem_lock);
wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
if (!wil->wmi_wq)
@@ -1390,13 +1413,22 @@ static int wil_get_otp_info(struct wil6210_priv *wil)
u8 mac[8];
int mac_addr;
- if (wil->hw_version >= HW_VER_TALYN_MB)
- mac_addr = RGF_OTP_MAC_TALYN_MB;
- else
- mac_addr = RGF_OTP_MAC;
+ /* OEM MAC has precedence */
+ mac_addr = RGF_OTP_OEM_MAC;
+ wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr), sizeof(mac));
+
+ if (is_valid_ether_addr(mac)) {
+ wil_info(wil, "using OEM MAC %pM\n", mac);
+ } else {
+ if (wil->hw_version >= HW_VER_TALYN_MB)
+ mac_addr = RGF_OTP_MAC_TALYN_MB;
+ else
+ mac_addr = RGF_OTP_MAC;
+
+ wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr),
+ sizeof(mac));
+ }
- wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr),
- sizeof(mac));
if (!is_valid_ether_addr(mac)) {
wil_err(wil, "Invalid MAC %pM\n", mac);
return -EINVAL;
@@ -1460,7 +1492,7 @@ void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync)
lockdep_assert_held(&wil->vif_mutex);
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
struct wil6210_vif *vif = wil->vifs[i];
if (vif)
@@ -1500,11 +1532,6 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
if (wil->hw_version < HW_VER_TALYN_MB) {
wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
- } else {
- wil_s(wil,
- RGF_CAF_ICR_TALYN_MB + offsetof(struct RGF_ICR, ICR), 0);
- wil_w(wil, RGF_CAF_ICR_TALYN_MB +
- offsetof(struct RGF_ICR, IMV), ~0);
}
/* clear PAL_UNIT_ICR (potential D0->D3 leftover)
* In Talyn-MB host cannot access this register due to
@@ -1528,7 +1555,7 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
struct wireless_dev *wdev;
int i, rc;
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i];
if (!vif)
continue;
@@ -1580,7 +1607,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
if (wil->hw_version == HW_VER_UNKNOWN)
return -ENODEV;
- if (test_bit(WIL_PLATFORM_CAPA_T_PWR_ON_0, wil->platform_capa)) {
+ if (test_bit(WIL_PLATFORM_CAPA_T_PWR_ON_0, wil->platform_capa) &&
+ wil->hw_version < HW_VER_TALYN_MB) {
wil_dbg_misc(wil, "Notify FW to set T_POWER_ON=0\n");
wil_s(wil, RGF_USER_USAGE_8, BIT_USER_SUPPORT_T_POWER_ON_0);
}
@@ -1599,20 +1627,11 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
}
set_bit(wil_status_resetting, wil->status);
- if (test_bit(wil_status_collecting_dumps, wil->status)) {
- /* Device collects crash dump, cancel the reset.
- * following crash dump collection, reset would take place.
- */
- wil_dbg_misc(wil, "reject reset while collecting crash dump\n");
- rc = -EBUSY;
- goto out;
- }
-
mutex_lock(&wil->vif_mutex);
wil_abort_scan_all_vifs(wil, false);
mutex_unlock(&wil->vif_mutex);
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i];
if (vif) {
cancel_work_sync(&vif->disconnect_worker);
@@ -1782,7 +1801,9 @@ int __wil_up(struct wil6210_priv *wil)
WARN_ON(!mutex_is_locked(&wil->mutex));
+ down_write(&wil->mem_lock);
rc = wil_reset(wil, true);
+ up_write(&wil->mem_lock);
if (rc)
return rc;
@@ -1854,6 +1875,7 @@ int wil_up(struct wil6210_priv *wil)
int __wil_down(struct wil6210_priv *wil)
{
+ int rc;
WARN_ON(!mutex_is_locked(&wil->mutex));
set_bit(wil_status_resetting, wil->status);
@@ -1873,7 +1895,11 @@ int __wil_down(struct wil6210_priv *wil)
wil_abort_scan_all_vifs(wil, false);
mutex_unlock(&wil->vif_mutex);
- return wil_reset(wil, false);
+ down_write(&wil->mem_lock);
+ rc = wil_reset(wil, false);
+ up_write(&wil->mem_lock);
+
+ return rc;
}
int wil_down(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index b4e0eb1585b9..59f041d708fe 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,7 +27,7 @@ bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
struct wil6210_vif *vif;
struct net_device *ndev_i;
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i];
if (vif) {
ndev_i = vif_to_ndev(vif);
@@ -155,7 +155,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
struct wil6210_vif *vif;
if (!ring->va || !txdata->enabled ||
- txdata->mid >= wil->max_vifs)
+ txdata->mid >= GET_MAX_VIFS(wil))
continue;
vif = wil->vifs[txdata->mid];
@@ -294,7 +294,7 @@ static u8 wil_vif_find_free_mid(struct wil6210_priv *wil)
{
u8 i;
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
if (!wil->vifs[i])
return i;
}
@@ -500,7 +500,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
bool any_active = wil_has_active_ifaces(wil, true, false);
ASSERT_RTNL();
- if (mid >= wil->max_vifs) {
+ if (mid >= GET_MAX_VIFS(wil)) {
wil_err(wil, "invalid MID: %d\n", mid);
return;
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index c8c6613371d1..3b82d6cfc218 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -176,7 +176,7 @@ static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
struct wil6210_vif *vif;
int i;
- for (i = 1; i < wil->max_vifs; i++) {
+ for (i = 1; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i];
if (vif) {
wil_vif_prepare_stop(vif);
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 75fe9323547c..56143e7670ed 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,7 +26,7 @@ static void wil_pm_wake_connected_net_queues(struct wil6210_priv *wil)
int i;
mutex_lock(&wil->vif_mutex);
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
struct wil6210_vif *vif = wil->vifs[i];
if (vif && test_bit(wil_vif_fwconnected, vif->status))
@@ -40,7 +40,7 @@ static void wil_pm_stop_all_net_queues(struct wil6210_priv *wil)
int i;
mutex_lock(&wil->vif_mutex);
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
struct wil6210_vif *vif = wil->vifs[i];
if (vif)
@@ -123,7 +123,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
/* interface is running */
mutex_lock(&wil->vif_mutex);
- for (i = 0; i < wil->max_vifs; i++) {
+ for (i = 0; i < GET_MAX_VIFS(wil); i++) {
struct wil6210_vif *vif = wil->vifs[i];
if (!vif)
@@ -195,14 +195,18 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
wil_dbg_pm(wil, "suspend keep radio on\n");
/* Prevent handling of new tx and wmi commands */
- set_bit(wil_status_suspending, wil->status);
- if (test_bit(wil_status_collecting_dumps, wil->status)) {
- /* Device collects crash dump, cancel the suspend */
- wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
- clear_bit(wil_status_suspending, wil->status);
+ rc = down_write_trylock(&wil->mem_lock);
+ if (!rc) {
+ wil_err(wil,
+ "device is busy. down_write_trylock failed, returned (0x%x)\n",
+ rc);
wil->suspend_stats.rejected_by_host++;
return -EBUSY;
}
+
+ set_bit(wil_status_suspending, wil->status);
+ up_write(&wil->mem_lock);
+
wil_pm_stop_all_net_queues(wil);
if (!wil_is_tx_idle(wil)) {
@@ -310,15 +314,18 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
wil_dbg_pm(wil, "suspend radio off\n");
- set_bit(wil_status_suspending, wil->status);
- if (test_bit(wil_status_collecting_dumps, wil->status)) {
- /* Device collects crash dump, cancel the suspend */
- wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
- clear_bit(wil_status_suspending, wil->status);
+ rc = down_write_trylock(&wil->mem_lock);
+ if (!rc) {
+ wil_err(wil,
+ "device is busy. down_write_trylock failed, returned (0x%x)\n",
+ rc);
wil->suspend_stats.rejected_by_host++;
return -EBUSY;
}
+ set_bit(wil_status_suspending, wil->status);
+ up_write(&wil->mem_lock);
+
/* if netif up, hardware is alive, shut it down */
mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index c38773878ae3..f6fce6ff73d9 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -29,6 +29,7 @@
#define WIL_EDMA_MAX_DATA_OFFSET (2)
/* RX buffer size must be aligned to 4 bytes */
#define WIL_EDMA_RX_BUF_LEN_DEFAULT (2048)
+#define MAX_INVALID_BUFF_ID_RETRY (3)
static void wil_tx_desc_unmap_edma(struct device *dev,
union wil_tx_desc *desc,
@@ -312,7 +313,8 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil,
struct list_head *free = &wil->rx_buff_mgmt.free;
int i;
- wil->rx_buff_mgmt.buff_arr = kcalloc(size, sizeof(struct wil_rx_buff),
+ wil->rx_buff_mgmt.buff_arr = kcalloc(size + 1,
+ sizeof(struct wil_rx_buff),
GFP_KERNEL);
if (!wil->rx_buff_mgmt.buff_arr)
return -ENOMEM;
@@ -321,14 +323,16 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil,
INIT_LIST_HEAD(active);
INIT_LIST_HEAD(free);
- /* Linkify the list */
+ /* Linkify the list.
+ * buffer id 0 should not be used (marks invalid id).
+ */
buff_arr = wil->rx_buff_mgmt.buff_arr;
- for (i = 0; i < size; i++) {
+ for (i = 1; i <= size; i++) {
list_add(&buff_arr[i].list, free);
buff_arr[i].id = i;
}
- wil->rx_buff_mgmt.size = size;
+ wil->rx_buff_mgmt.size = size + 1;
return 0;
}
@@ -428,6 +432,9 @@ static void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring)
&ring->pa, ring->ctx);
wil_move_all_rx_buff_to_free_list(wil, ring);
+ dma_free_coherent(dev, sizeof(*ring->edma_rx_swtail.va),
+ ring->edma_rx_swtail.va,
+ ring->edma_rx_swtail.pa);
goto out;
}
@@ -804,18 +811,9 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil,
struct sk_buff *skb,
struct wil_net_stats *stats)
{
- int error;
int l2_rx_status;
- int l3_rx_status;
- int l4_rx_status;
void *msg = wil_skb_rxstatus(skb);
- error = wil_rx_status_get_error(msg);
- if (!error) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- return 0;
- }
-
l2_rx_status = wil_rx_status_get_l2_rx_status(msg);
if (l2_rx_status != 0) {
wil_dbg_txrx(wil, "L2 RX error, l2_rx_status=0x%x\n",
@@ -844,17 +842,7 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil,
return -EFAULT;
}
- l3_rx_status = wil_rx_status_get_l3_rx_status(msg);
- l4_rx_status = wil_rx_status_get_l4_rx_status(msg);
- if (!l3_rx_status && !l4_rx_status)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- /* If HW reports bad checksum, let IP stack re-check it
- * For example, HW don't understand Microsoft IP stack that
- * mis-calculates TCP checksum - if it should be 0x0,
- * it writes 0xffff in violation of RFC 1624
- */
- else
- stats->rx_csum_err++;
+ skb->ip_summed = wil_rx_status_get_checksum(msg, stats);
return 0;
}
@@ -892,26 +880,50 @@ again:
/* Extract the buffer ID from the status message */
buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg));
- if (unlikely(!wil_val_in_range(buff_id, 0, wil->rx_buff_mgmt.size))) {
+
+ while (!buff_id) {
+ struct wil_rx_status_extended *s;
+ int invalid_buff_id_retry = 0;
+
+ wil_dbg_txrx(wil,
+ "buff_id is not updated yet by HW, (swhead 0x%x)\n",
+ sring->swhead);
+ if (++invalid_buff_id_retry > MAX_INVALID_BUFF_ID_RETRY)
+ break;
+
+ /* Read the status message again */
+ s = (struct wil_rx_status_extended *)
+ (sring->va + (sring->elem_size * sring->swhead));
+ *(struct wil_rx_status_extended *)msg = *s;
+ buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg));
+ }
+
+ if (unlikely(!wil_val_in_range(buff_id, 1, wil->rx_buff_mgmt.size))) {
wil_err(wil, "Corrupt buff_id=%d, sring->swhead=%d\n",
buff_id, sring->swhead);
+ wil_rx_status_reset_buff_id(sring);
wil_sring_advance_swhead(sring);
+ sring->invalid_buff_id_cnt++;
goto again;
}
- wil_sring_advance_swhead(sring);
-
/* Extract the SKB from the rx_buff management array */
skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
if (!skb) {
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
+ wil_rx_status_reset_buff_id(sring);
/* Move the buffer from the active list to the free list */
- list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
- &wil->rx_buff_mgmt.free);
+ list_move_tail(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
+ &wil->rx_buff_mgmt.free);
+ wil_sring_advance_swhead(sring);
+ sring->invalid_buff_id_cnt++;
goto again;
}
+ wil_rx_status_reset_buff_id(sring);
+ wil_sring_advance_swhead(sring);
+
memcpy(&pa, skb->cb, sizeof(pa));
dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
dmalen = le16_to_cpu(wil_rx_status_get_length(msg));
@@ -926,8 +938,8 @@ again:
sizeof(struct wil_rx_status_extended), false);
/* Move the buffer from the active list to the free list */
- list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
- &wil->rx_buff_mgmt.free);
+ list_move_tail(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
+ &wil->rx_buff_mgmt.free);
eop = wil_rx_status_get_eop(msg);
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h
index 343516a03a1e..bb4ff28b73e5 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.h
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016,2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2016,2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -427,6 +427,12 @@ static inline int wil_rx_status_get_eop(void *msg) /* EoP = End of Packet */
30, 30);
}
+static inline void wil_rx_status_reset_buff_id(struct wil_status_ring *s)
+{
+ ((struct wil_rx_status_compressed *)
+ (s->va + (s->elem_size * s->swhead)))->buff_id = 0;
+}
+
static inline __le16 wil_rx_status_get_buff_id(void *msg)
{
return ((struct wil_rx_status_compressed *)msg)->buff_id;
@@ -511,6 +517,45 @@ static inline int wil_rx_status_get_l4_rx_status(void *msg)
5, 6);
}
+/* L4 L3 Expected result
+ * 0 0 Ok. No L3 and no L4 known protocols found.
+ * Treated as L2 packet. (no offloads on this packet)
+ * 0 1 Ok. It means that L3 was found, and checksum check passed.
+ * No known L4 protocol was found.
+ * 0 2 It means that L3 protocol was found, and checksum check failed.
+ * No L4 known protocol was found.
+ * 1 any Ok. It means that L4 was found, and checksum check passed.
+ * 3 0 Not a possible scenario.
+ * 3 1 Recalculate. It means that L3 protocol was found, and checksum
+ * passed. But L4 checksum failed. Need to see if really failed,
+ * or due to fragmentation.
+ * 3 2 Both L3 and L4 checksum check failed.
+ */
+static inline int wil_rx_status_get_checksum(void *msg,
+ struct wil_net_stats *stats)
+{
+ int l3_rx_status = wil_rx_status_get_l3_rx_status(msg);
+ int l4_rx_status = wil_rx_status_get_l4_rx_status(msg);
+
+ if (l4_rx_status == 1)
+ return CHECKSUM_UNNECESSARY;
+
+ if (l4_rx_status == 0 && l3_rx_status == 1)
+ return CHECKSUM_UNNECESSARY;
+
+ if (l3_rx_status == 0 && l4_rx_status == 0)
+ /* L2 packet */
+ return CHECKSUM_NONE;
+
+ /* If HW reports bad checksum, let IP stack re-check it
+ * For example, HW doesn't understand Microsoft IP stack that
+ * mis-calculates TCP checksum - if it should be 0x0,
+ * it writes 0xffff in violation of RFC 1624
+ */
+ stats->rx_csum_err++;
+ return CHECKSUM_NONE;
+}
+
static inline int wil_rx_status_get_security(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index e1b1039b13ab..8724d9975606 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -185,6 +185,7 @@ struct RGF_ICR {
/* registers - FW addresses */
#define RGF_USER_USAGE_1 (0x880004)
+#define RGF_USER_USAGE_2 (0x880008)
#define RGF_USER_USAGE_6 (0x880018)
#define BIT_USER_OOB_MODE BIT(31)
#define BIT_USER_OOB_R2_MODE BIT(30)
@@ -367,6 +368,7 @@ struct RGF_ICR {
#define REVISION_ID_SPARROW_D0 (0x3)
#define RGF_OTP_MAC_TALYN_MB (0x8a0304)
+#define RGF_OTP_OEM_MAC (0x8a0334)
#define RGF_OTP_MAC (0x8a0620)
/* Talyn-MB */
@@ -566,10 +568,11 @@ struct wil_status_ring {
bool is_rx;
u8 desc_rdy_pol; /* Expected descriptor ready bit polarity */
struct wil_ring_rx_data rx_data;
+ u32 invalid_buff_id_cnt; /* relevant only for RX */
};
#define WIL_STA_TID_NUM (16)
-#define WIL_MCS_MAX (12) /* Maximum MCS supported */
+#define WIL_MCS_MAX (15) /* Maximum MCS supported */
struct wil_net_stats {
unsigned long rx_packets;
@@ -660,7 +663,6 @@ enum { /* for wil6210_priv.status */
wil_status_suspending, /* suspend in progress */
wil_status_suspended, /* suspend completed, device is suspended */
wil_status_resuming, /* resume in progress */
- wil_status_collecting_dumps, /* crashdump collection in progress */
wil_status_last /* keep last */
};
@@ -992,6 +994,8 @@ struct wil6210_priv {
struct wil_txrx_ops txrx_ops;
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
+ /* for synchronizing device memory access while reset or suspend */
+ struct rw_semaphore mem_lock;
/* statistics */
atomic_t isr_count_rx, isr_count_tx;
/* debugfs */
@@ -1060,6 +1064,7 @@ struct wil6210_priv {
#define vif_to_wil(v) (v->wil)
#define vif_to_ndev(v) (v->ndev)
#define vif_to_wdev(v) (&v->wdev)
+#define GET_MAX_VIFS(wil) min_t(int, (wil)->max_vifs, WIL_MAX_VIFS)
static inline struct wil6210_vif *wdev_to_vif(struct wil6210_priv *wil,
struct wireless_dev *wdev)
@@ -1176,6 +1181,8 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
size_t count);
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count);
+int wil_mem_access_lock(struct wil6210_priv *wil);
+void wil_mem_access_unlock(struct wil6210_priv *wil);
struct wil6210_vif *
wil_vif_alloc(struct wil6210_priv *wil, const char *name,
diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
index dc33a0b4c3fa..772cb00c2002 100644
--- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
+++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2015,2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -57,7 +57,7 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil,
int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
{
- int i;
+ int i, rc;
const struct fw_map *map;
void *data;
u32 host_min, dump_size, offset, len;
@@ -73,14 +73,9 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
return -EINVAL;
}
- set_bit(wil_status_collecting_dumps, wil->status);
- if (test_bit(wil_status_suspending, wil->status) ||
- test_bit(wil_status_suspended, wil->status) ||
- test_bit(wil_status_resetting, wil->status)) {
- wil_err(wil, "cannot collect fw dump during suspend/reset\n");
- clear_bit(wil_status_collecting_dumps, wil->status);
- return -EINVAL;
- }
+ rc = wil_mem_access_lock(wil);
+ if (rc)
+ return rc;
/* copy to crash dump area */
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
@@ -100,8 +95,7 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
wil_memcpy_fromio_32((void * __force)(dest + offset),
(const void __iomem * __force)data, len);
}
-
- clear_bit(wil_status_collecting_dumps, wil->status);
+ wil_mem_access_unlock(wil);
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index bda4a9712f91..d89cd41e78ac 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -41,6 +41,7 @@ MODULE_PARM_DESC(led_id,
#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
#define WIL_WMI_CALL_GENERAL_TO_MS 100
+#define WIL_WMI_PCP_STOP_TO_MS 5000
/**
* WMI event receiving - theory of operations
@@ -2195,7 +2196,8 @@ int wmi_pcp_stop(struct wil6210_vif *vif)
return rc;
return wmi_call(wil, WMI_PCP_STOP_CMDID, vif->mid, NULL, 0,
- WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
+ WMI_PCP_STOPPED_EVENTID, NULL, 0,
+ WIL_WMI_PCP_STOP_TO_MS);
}
int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid)
@@ -2957,6 +2959,10 @@ static const char *suspend_status2name(u8 status)
switch (status) {
case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
return "LINK_NOT_IDLE";
+ case WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT:
+ return "DISCONNECT";
+ case WMI_TRAFFIC_SUSPEND_REJECTED_OTHER:
+ return "OTHER";
default:
return "Untracked status";
}
@@ -3046,6 +3052,9 @@ static void resume_triggers2string(u32 triggers, char *string, int str_size)
if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
strlcat(string, " WMI_EVT", str_size);
+
+ if (triggers & WMI_RESUME_TRIGGER_DISCONNECT)
+ strlcat(string, " DISCONNECT", str_size);
}
int wmi_resume(struct wil6210_priv *wil)
@@ -3196,7 +3205,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
if (mid == MID_BROADCAST)
mid = 0;
- if (mid >= ARRAY_SIZE(wil->vifs) || mid >= wil->max_vifs) {
+ if (mid >= GET_MAX_VIFS(wil)) {
wil_dbg_wmi(wil, "invalid mid %d, event skipped\n",
mid);
return;
@@ -3502,8 +3511,9 @@ int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len)
rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, vif->mid, cmd, total,
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) {
- wil_err(wil, "mgmt_tx failed with status %d\n", evt.evt.status);
- rc = -EINVAL;
+ wil_dbg_wmi(wil, "mgmt_tx failed with status %d\n",
+ evt.evt.status);
+ rc = -EAGAIN;
}
kfree(cmd);
@@ -3555,9 +3565,9 @@ int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
rc = wmi_call(wil, WMI_SW_TX_REQ_EXT_CMDID, vif->mid, cmd, total,
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) {
- wil_err(wil, "mgmt_tx_ext failed with status %d\n",
- evt.evt.status);
- rc = -EINVAL;
+ wil_dbg_wmi(wil, "mgmt_tx_ext failed with status %d\n",
+ evt.evt.status);
+ rc = -EAGAIN;
}
kfree(cmd);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index b668758da994..da46fc8d39cf 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity
*
@@ -104,6 +104,7 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_RAW_MODE = 24,
WMI_FW_CAPABILITY_TX_REQ_EXT = 25,
WMI_FW_CAPABILITY_CHANNEL_4 = 26,
+ WMI_FW_CAPABILITY_IPA = 27,
WMI_FW_CAPABILITY_MAX,
};
@@ -294,6 +295,7 @@ enum wmi_command_id {
WMI_SET_AP_SLOT_SIZE_CMDID = 0xA0F,
WMI_SET_VRING_PRIORITY_WEIGHT_CMDID = 0xA10,
WMI_SET_VRING_PRIORITY_CMDID = 0xA11,
+ WMI_RBUFCAP_CFG_CMDID = 0xA12,
WMI_SET_MAC_ADDRESS_CMDID = 0xF003,
WMI_ABORT_SCAN_CMDID = 0xF007,
WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041,
@@ -979,10 +981,22 @@ enum wmi_rx_msg_type {
WMI_RX_MSG_TYPE_EXTENDED = 0x01,
};
+enum wmi_ring_add_irq_mode {
+ /* Backwards compatibility
+ * for DESC ring - interrupt disabled
+ * for STATUS ring - interrupt enabled
+ */
+ WMI_RING_ADD_IRQ_MODE_BWC = 0x00,
+ WMI_RING_ADD_IRQ_MODE_DISABLE = 0x01,
+ WMI_RING_ADD_IRQ_MODE_ENABLE = 0x02,
+};
+
struct wmi_tx_status_ring_add_cmd {
struct wmi_edma_ring_cfg ring_cfg;
u8 irq_index;
- u8 reserved[3];
+ /* wmi_ring_add_irq_mode */
+ u8 irq_mode;
+ u8 reserved[2];
} __packed;
struct wmi_rx_status_ring_add_cmd {
@@ -1016,7 +1030,10 @@ struct wmi_tx_desc_ring_add_cmd {
u8 mac_ctrl;
u8 to_resolution;
u8 agg_max_wsize;
- u8 reserved[3];
+ u8 irq_index;
+ /* wmi_ring_add_irq_mode */
+ u8 irq_mode;
+ u8 reserved;
struct wmi_vring_cfg_schd schd_params;
} __packed;
@@ -1982,6 +1999,7 @@ enum wmi_event_id {
WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836,
WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
+ WMI_BF_TRIG_EVENTID = 0x183A,
WMI_RS_MGMT_DONE_EVENTID = 0x1852,
WMI_RF_MGMT_STATUS_EVENTID = 0x1853,
WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838,
@@ -2082,6 +2100,7 @@ enum wmi_event_id {
WMI_SET_AP_SLOT_SIZE_EVENTID = 0x1A0F,
WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID = 0x1A10,
WMI_SET_VRING_PRIORITY_EVENTID = 0x1A11,
+ WMI_RBUFCAP_CFG_EVENTID = 0x1A12,
WMI_SET_CHANNEL_EVENTID = 0x9000,
WMI_ASSOC_REQ_EVENTID = 0x9001,
WMI_EAPOL_RX_EVENTID = 0x9002,
@@ -2267,7 +2286,9 @@ struct wmi_notify_req_done_event {
__le32 status;
__le64 tsf;
s8 rssi;
- u8 reserved0[3];
+ /* enum wmi_edmg_tx_mode */
+ u8 tx_mode;
+ u8 reserved0[2];
__le32 tx_tpt;
__le32 tx_goodput;
__le32 rx_goodput;
@@ -2316,6 +2337,7 @@ enum wmi_disconnect_reason {
WMI_DIS_REASON_PROFILE_MISMATCH = 0x0C,
WMI_DIS_REASON_CONNECTION_EVICTED = 0x0D,
WMI_DIS_REASON_IBSS_MERGE = 0x0E,
+ WMI_DIS_REASON_HIGH_TEMPERATURE = 0x0F,
};
/* WMI_DISCONNECT_EVENTID */
@@ -3168,6 +3190,30 @@ struct wmi_brp_set_ant_limit_event {
u8 reserved[3];
} __packed;
+enum wmi_bf_type {
+ WMI_BF_TYPE_SLS = 0x00,
+ WMI_BF_TYPE_BRP_RX = 0x01,
+};
+
+/* WMI_BF_TRIG_CMDID */
+struct wmi_bf_trig_cmd {
+ /* enum wmi_bf_type - type of requested beamforming */
+ u8 bf_type;
+ /* used only for WMI_BF_TYPE_BRP_RX */
+ u8 cid;
+ /* used only for WMI_BF_TYPE_SLS */
+ u8 dst_mac[WMI_MAC_LEN];
+ u8 reserved[4];
+} __packed;
+
+/* WMI_BF_TRIG_EVENTID */
+struct wmi_bf_trig_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ u8 cid;
+ u8 reserved[2];
+} __packed;
+
/* broadcast connection ID */
#define WMI_LINK_MAINTAIN_CFG_CID_BROADCAST (0xFFFFFFFF)
@@ -3263,6 +3309,8 @@ struct wmi_link_maintain_cfg_read_done_event {
enum wmi_traffic_suspend_status {
WMI_TRAFFIC_SUSPEND_APPROVED = 0x0,
WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE = 0x1,
+ WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT = 0x2,
+ WMI_TRAFFIC_SUSPEND_REJECTED_OTHER = 0x3,
};
/* WMI_TRAFFIC_SUSPEND_EVENTID */
@@ -3282,6 +3330,7 @@ enum wmi_resume_trigger {
WMI_RESUME_TRIGGER_UCAST_RX = 0x2,
WMI_RESUME_TRIGGER_BCAST_RX = 0x4,
WMI_RESUME_TRIGGER_WMI_EVT = 0x8,
+ WMI_RESUME_TRIGGER_DISCONNECT = 0x10,
};
/* WMI_TRAFFIC_RESUME_EVENTID */
@@ -4057,4 +4106,38 @@ struct wmi_set_vring_priority_event {
u8 reserved[3];
} __packed;
+/* WMI_RADAR_PCI_CTRL_BLOCK struct */
+struct wmi_radar_pci_ctrl_block {
+ /* last fw tail address index */
+ __le32 fw_tail_index;
+ /* last SW head address index known to FW */
+ __le32 sw_head_index;
+ __le32 last_wr_pulse_tsf_low;
+ __le32 last_wr_pulse_count;
+ __le32 last_wr_in_bytes;
+ __le32 last_wr_pulse_id;
+ __le32 last_wr_burst_id;
+ /* When pre overflow detected, advance sw head in unit of pulses */
+ __le32 sw_head_inc;
+ __le32 reserved[8];
+} __packed;
+
+/* WMI_RBUFCAP_CFG_CMD */
+struct wmi_rbufcap_cfg_cmd {
+ u8 enable;
+ u8 reserved;
+ /* RBUFCAP indicates rx space unavailable when number of rx
+ * descriptors drops below this threshold. Set 0 to use system
+ * default
+ */
+ __le16 rx_desc_threshold;
+} __packed;
+
+/* WMI_RBUFCAP_CFG_EVENTID */
+struct wmi_rbufcap_cfg_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
#endif /* __WILOCITY_WMI_H__ */