Commit db5e323f authored by Kalle Valo's avatar Kalle Valo

Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for 5.2. No major changes.
parents 5c2e6e14 fa0b7354
...@@ -465,7 +465,7 @@ static int wil_cfg80211_validate_add_iface(struct wil6210_priv *wil, ...@@ -465,7 +465,7 @@ static int wil_cfg80211_validate_add_iface(struct wil6210_priv *wil,
.num_different_channels = 1, .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]) { if (wil->vifs[i]) {
wdev = vif_to_wdev(wil->vifs[i]); wdev = vif_to_wdev(wil->vifs[i]);
params.iftype_num[wdev->iftype]++; params.iftype_num[wdev->iftype]++;
...@@ -486,7 +486,7 @@ static int wil_cfg80211_validate_change_iface(struct wil6210_priv *wil, ...@@ -486,7 +486,7 @@ static int wil_cfg80211_validate_change_iface(struct wil6210_priv *wil,
}; };
bool check_combos = false; 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]; struct wil6210_vif *vif_pos = wil->vifs[i];
if (vif_pos && vif != vif_pos) { if (vif_pos && vif != vif_pos) {
...@@ -1274,7 +1274,12 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, ...@@ -1274,7 +1274,12 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
params->wait); params->wait);
out: 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); tx_status = (rc == 0);
rc = (rc == -EAGAIN) ? 0 : rc;
cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len, cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
tx_status, GFP_KERNEL); tx_status, GFP_KERNEL);
...@@ -1806,7 +1811,7 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil) ...@@ -1806,7 +1811,7 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
int rc, i; int rc, i;
struct wiphy *wiphy = wil_to_wiphy(wil); 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 wil6210_vif *vif = wil->vifs[i];
struct net_device *ndev; struct net_device *ndev;
struct cfg80211_beacon_data bcon = {}; struct cfg80211_beacon_data bcon = {};
......
...@@ -207,6 +207,8 @@ static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil, ...@@ -207,6 +207,8 @@ static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil,
seq_puts(s, "???\n"); seq_puts(s, "???\n");
} }
seq_printf(s, " desc_rdy_pol = %d\n", sring->desc_rdy_pol); 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))) { if (sring->va && (sring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
uint i; uint i;
...@@ -258,6 +260,11 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix, ...@@ -258,6 +260,11 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
wil_halp_vote(wil); wil_halp_vote(wil);
if (wil_mem_access_lock(wil)) {
wil_halp_unvote(wil);
return;
}
wil_memcpy_fromio_32(&r, off, sizeof(r)); wil_memcpy_fromio_32(&r, off, sizeof(r));
wil_mbox_ring_le2cpus(&r); wil_mbox_ring_le2cpus(&r);
/* /*
...@@ -323,6 +330,7 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix, ...@@ -323,6 +330,7 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
} }
out: out:
seq_puts(s, "}\n"); seq_puts(s, "}\n");
wil_mem_access_unlock(wil);
wil_halp_unvote(wil); wil_halp_unvote(wil);
} }
...@@ -601,6 +609,12 @@ static int memread_show(struct seq_file *s, void *data) ...@@ -601,6 +609,12 @@ static int memread_show(struct seq_file *s, void *data)
if (ret < 0) if (ret < 0)
return ret; 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)); a = wmi_buffer(wil, cpu_to_le32(mem_addr));
if (a) if (a)
...@@ -608,6 +622,7 @@ static int memread_show(struct seq_file *s, void *data) ...@@ -608,6 +622,7 @@ static int memread_show(struct seq_file *s, void *data)
else else
seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
wil_mem_access_unlock(wil);
wil_pm_runtime_put(wil); wil_pm_runtime_put(wil);
return 0; return 0;
...@@ -626,10 +641,6 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, ...@@ -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; size_t unaligned_bytes, aligned_count, ret;
int rc; 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) if (pos < 0)
return -EINVAL; return -EINVAL;
...@@ -656,11 +667,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, ...@@ -656,11 +667,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
return rc; 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_memcpy_fromio_32(buf, (const void __iomem *)
wil_blob->blob.data + aligned_pos, aligned_count); wil_blob->blob.data + aligned_pos, aligned_count);
ret = copy_to_user(user_buf, buf + unaligned_bytes, count); ret = copy_to_user(user_buf, buf + unaligned_bytes, count);
wil_mem_access_unlock(wil);
wil_pm_runtime_put(wil); wil_pm_runtime_put(wil);
kfree(buf); kfree(buf);
...@@ -1364,7 +1383,7 @@ static int link_show(struct seq_file *s, void *data) ...@@ -1364,7 +1383,7 @@ static int link_show(struct seq_file *s, void *data)
if (p->status != wil_sta_connected) if (p->status != wil_sta_connected)
continue; continue;
vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL; vif = (mid < GET_MAX_VIFS(wil)) ? wil->vifs[mid] : NULL;
if (vif) { if (vif) {
rc = wil_cid_fill_sinfo(vif, i, sinfo); rc = wil_cid_fill_sinfo(vif, i, sinfo);
if (rc) if (rc)
...@@ -1562,7 +1581,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) ...@@ -1562,7 +1581,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
break; break;
} }
mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; 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]; struct wil6210_vif *vif = wil->vifs[mid];
if (vif->wdev.iftype == NL80211_IFTYPE_STATION && if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
...@@ -1628,7 +1647,7 @@ static int mids_show(struct seq_file *s, void *data) ...@@ -1628,7 +1647,7 @@ static int mids_show(struct seq_file *s, void *data)
int i; int i;
mutex_lock(&wil->vif_mutex); 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]; vif = wil->vifs[i];
if (vif) { if (vif) {
...@@ -1849,7 +1868,7 @@ static int wil_link_stats_debugfs_show(struct seq_file *s, void *data) ...@@ -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 /* iterate over all MIDs and show per-cid statistics. Then show the
* global statistics * global statistics
*/ */
for (i = 0; i < wil->max_vifs; i++) { for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i]; vif = wil->vifs[i];
seq_printf(s, "MID %d ", 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, ...@@ -1905,7 +1924,7 @@ static ssize_t wil_link_stats_write(struct file *file, const char __user *buf,
if (rc) if (rc)
return rc; return rc;
for (i = 0; i < wil->max_vifs; i++) { for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i]; vif = wil->vifs[i];
if (!vif) if (!vif)
continue; continue;
...@@ -2375,6 +2394,7 @@ static const struct dbg_off dbg_wil_regs[] = { ...@@ -2375,6 +2394,7 @@ static const struct dbg_off dbg_wil_regs[] = {
{"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0), {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
doff_io32}, doff_io32},
{"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), 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},
{}, {},
}; };
......
/* /*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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, ...@@ -647,6 +647,8 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
out: out:
release_firmware(fw); release_firmware(fw);
if (rc)
wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc);
return rc; return rc;
} }
...@@ -741,6 +743,8 @@ int wil_request_board(struct wil6210_priv *wil, const char *name) ...@@ -741,6 +743,8 @@ int wil_request_board(struct wil6210_priv *wil, const char *name)
out: out:
release_firmware(brd); release_firmware(brd);
if (rc)
wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc);
return rc; return rc;
} }
......
...@@ -184,6 +184,28 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, ...@@ -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) static void wil_ring_fini_tx(struct wil6210_priv *wil, int id)
{ {
struct wil_ring *ring = &wil->ring_tx[id]; struct wil_ring *ring = &wil->ring_tx[id];
...@@ -663,7 +685,7 @@ void wil_bcast_fini_all(struct wil6210_priv *wil) ...@@ -663,7 +685,7 @@ void wil_bcast_fini_all(struct wil6210_priv *wil)
int i; int i;
struct wil6210_vif *vif; 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]; vif = wil->vifs[i];
if (vif) if (vif)
wil_bcast_fini(vif); wil_bcast_fini(vif);
...@@ -703,6 +725,7 @@ int wil_priv_init(struct wil6210_priv *wil) ...@@ -703,6 +725,7 @@ int wil_priv_init(struct wil6210_priv *wil)
spin_lock_init(&wil->wmi_ev_lock); spin_lock_init(&wil->wmi_ev_lock);
spin_lock_init(&wil->net_queue_lock); spin_lock_init(&wil->net_queue_lock);
init_waitqueue_head(&wil->wq); init_waitqueue_head(&wil->wq);
init_rwsem(&wil->mem_lock);
wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
if (!wil->wmi_wq) if (!wil->wmi_wq)
...@@ -1390,13 +1413,22 @@ static int wil_get_otp_info(struct wil6210_priv *wil) ...@@ -1390,13 +1413,22 @@ static int wil_get_otp_info(struct wil6210_priv *wil)
u8 mac[8]; u8 mac[8];
int mac_addr; int mac_addr;
if (wil->hw_version >= HW_VER_TALYN_MB) /* OEM MAC has precedence */
mac_addr = RGF_OTP_MAC_TALYN_MB; mac_addr = RGF_OTP_OEM_MAC;
else wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr), sizeof(mac));
mac_addr = RGF_OTP_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)) { if (!is_valid_ether_addr(mac)) {
wil_err(wil, "Invalid MAC %pM\n", mac); wil_err(wil, "Invalid MAC %pM\n", mac);
return -EINVAL; return -EINVAL;
...@@ -1460,7 +1492,7 @@ void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync) ...@@ -1460,7 +1492,7 @@ void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync)
lockdep_assert_held(&wil->vif_mutex); 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]; struct wil6210_vif *vif = wil->vifs[i];
if (vif) if (vif)
...@@ -1500,11 +1532,6 @@ static void wil_pre_fw_config(struct wil6210_priv *wil) ...@@ -1500,11 +1532,6 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
if (wil->hw_version < HW_VER_TALYN_MB) { if (wil->hw_version < HW_VER_TALYN_MB) {
wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~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) /* clear PAL_UNIT_ICR (potential D0->D3 leftover)
* In Talyn-MB host cannot access this register due to * In Talyn-MB host cannot access this register due to
...@@ -1528,7 +1555,7 @@ static int wil_restore_vifs(struct wil6210_priv *wil) ...@@ -1528,7 +1555,7 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
struct wireless_dev *wdev; struct wireless_dev *wdev;
int i, rc; int i, rc;
for (i = 0; i < wil->max_vifs; i++) { for (i = 0; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i]; vif = wil->vifs[i];
if (!vif) if (!vif)
continue; continue;
...@@ -1580,7 +1607,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1580,7 +1607,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
if (wil->hw_version == HW_VER_UNKNOWN) if (wil->hw_version == HW_VER_UNKNOWN)
return -ENODEV; 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_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); 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) ...@@ -1599,20 +1627,11 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
} }
set_bit(wil_status_resetting, wil->status); 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); mutex_lock(&wil->vif_mutex);
wil_abort_scan_all_vifs(wil, false); wil_abort_scan_all_vifs(wil, false);
mutex_unlock(&wil->vif_mutex); 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]; vif = wil->vifs[i];
if (vif) { if (vif) {
cancel_work_sync(&vif->disconnect_worker); cancel_work_sync(&vif->disconnect_worker);
...@@ -1782,7 +1801,9 @@ int __wil_up(struct wil6210_priv *wil) ...@@ -1782,7 +1801,9 @@ int __wil_up(struct wil6210_priv *wil)
WARN_ON(!mutex_is_locked(&wil->mutex)); WARN_ON(!mutex_is_locked(&wil->mutex));
down_write(&wil->mem_lock);
rc = wil_reset(wil, true); rc = wil_reset(wil, true);
up_write(&wil->mem_lock);
if (rc) if (rc)
return rc; return rc;
...@@ -1854,6 +1875,7 @@ int wil_up(struct wil6210_priv *wil) ...@@ -1854,6 +1875,7 @@ int wil_up(struct wil6210_priv *wil)
int __wil_down(struct wil6210_priv *wil) int __wil_down(struct wil6210_priv *wil)
{ {
int rc;
WARN_ON(!mutex_is_locked(&wil->mutex)); WARN_ON(!mutex_is_locked(&wil->mutex));
set_bit(wil_status_resetting, wil->status); set_bit(wil_status_resetting, wil->status);
...@@ -1873,7 +1895,11 @@ int __wil_down(struct wil6210_priv *wil) ...@@ -1873,7 +1895,11 @@ int __wil_down(struct wil6210_priv *wil)
wil_abort_scan_all_vifs(wil, false); wil_abort_scan_all_vifs(wil, false);
mutex_unlock(&wil->vif_mutex); 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) int wil_down(struct wil6210_priv *wil)
......
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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, ...@@ -27,7 +27,7 @@ bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
struct wil6210_vif *vif; struct wil6210_vif *vif;
struct net_device *ndev_i; 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]; vif = wil->vifs[i];
if (vif) { if (vif) {
ndev_i = vif_to_ndev(vif); ndev_i = vif_to_ndev(vif);
...@@ -155,7 +155,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) ...@@ -155,7 +155,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
struct wil6210_vif *vif; struct wil6210_vif *vif;
if (!ring->va || !txdata->enabled || if (!ring->va || !txdata->enabled ||
txdata->mid >= wil->max_vifs) txdata->mid >= GET_MAX_VIFS(wil))
continue; continue;
vif = wil->vifs[txdata->mid]; vif = wil->vifs[txdata->mid];
...@@ -294,7 +294,7 @@ static u8 wil_vif_find_free_mid(struct wil6210_priv *wil) ...@@ -294,7 +294,7 @@ static u8 wil_vif_find_free_mid(struct wil6210_priv *wil)
{ {
u8 i; u8 i;
for (i = 0; i < wil->max_vifs; i++) { for (i = 0; i < GET_MAX_VIFS(wil); i++) {
if (!wil->vifs[i]) if (!wil->vifs[i])
return i; return i;
} }
...@@ -500,7 +500,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid) ...@@ -500,7 +500,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
bool any_active = wil_has_active_ifaces(wil, true, false); bool any_active = wil_has_active_ifaces(wil, true, false);
ASSERT_RTNL(); ASSERT_RTNL();
if (mid >= wil->max_vifs) { if (mid >= GET_MAX_VIFS(wil)) {
wil_err(wil, "invalid MID: %d\n", mid); wil_err(wil, "invalid MID: %d\n", mid);
return; return;
} }
......
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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) ...@@ -176,7 +176,7 @@ static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
struct wil6210_vif *vif; struct wil6210_vif *vif;
int i; int i;
for (i = 1; i < wil->max_vifs; i++) { for (i = 1; i < GET_MAX_VIFS(wil); i++) {
vif = wil->vifs[i]; vif = wil->vifs[i];
if (vif) { if (vif) {
wil_vif_prepare_stop(vif); wil_vif_prepare_stop(vif);
......
/* /*
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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) ...@@ -26,7 +26,7 @@ static void wil_pm_wake_connected_net_queues(struct wil6210_priv *wil)
int i; int i;
mutex_lock(&wil->vif_mutex); 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]; struct wil6210_vif *vif = wil->vifs[i];
if (vif && test_bit(wil_vif_fwconnected, vif->status)) 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) ...@@ -40,7 +40,7 @@ static void wil_pm_stop_all_net_queues(struct wil6210_priv *wil)
int i; int i;
mutex_lock(&wil->vif_mutex); 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]; struct wil6210_vif *vif = wil->vifs[i];
if (vif) if (vif)
...@@ -123,7 +123,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) ...@@ -123,7 +123,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
/* interface is running */ /* interface is running */
mutex_lock(&wil->vif_mutex); 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]; struct wil6210_vif *vif = wil->vifs[i];
if (!vif) if (!vif)
...@@ -195,14 +195,18 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) ...@@ -195,14 +195,18 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
wil_dbg_pm(wil, "suspend keep radio on\n"); wil_dbg_pm(wil, "suspend keep radio on\n");
/* Prevent handling of new tx and wmi commands */ /* Prevent handling of new tx and wmi commands */
set_bit(wil_status_suspending, wil->status); rc = down_write_trylock(&wil->mem_lock);
if (test_bit(wil_status_collecting_dumps, wil->status)) { if (!rc) {
/* Device collects crash dump, cancel the suspend */ wil_err(wil,
wil_dbg_pm(wil, "reject suspend while collecting crash dump\n"); "device is busy. down_write_trylock failed, returned (0x%x)\n",
clear_bit(wil_status_suspending, wil->status); rc);
wil->suspend_stats.rejected_by_host++; wil->suspend_stats.rejected_by_host++;
return -EBUSY; return -EBUSY;
} }
set_bit(wil_status_suspending, wil->status);
up_write(&wil->mem_lock);
wil_pm_stop_all_net_queues(wil); wil_pm_stop_all_net_queues(wil);
if (!wil_is_tx_idle(wil)) { if (!wil_is_tx_idle(wil)) {
...@@ -310,15 +314,18 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil) ...@@ -310,15 +314,18 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
wil_dbg_pm(wil, "suspend radio off\n"); wil_dbg_pm(wil, "suspend radio off\n");
set_bit(wil_status_suspending, wil->status); rc = down_write_trylock(&wil->mem_lock);
if (test_bit(wil_status_collecting_dumps, wil->status)) { if (!rc) {
/* Device collects crash dump, cancel the suspend */ wil_err(wil,
wil_dbg_pm(wil, "reject suspend while collecting crash dump\n"); "device is busy. down_write_trylock failed, returned (0x%x)\n",
clear_bit(wil_status_suspending, wil->status); rc);
wil->suspend_stats.rejected_by_host++; wil->suspend_stats.rejected_by_host++;
return -EBUSY; return -EBUSY;
} }
set_bit(wil_status_suspending, wil->status);
up_write(&wil->mem_lock);
/* if netif up, hardware is alive, shut it down */ /* if netif up, hardware is alive, shut it down */
mutex_lock(&wil->vif_mutex); mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false); active_ifaces = wil_has_active_ifaces(wil, true, false);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define WIL_EDMA_MAX_DATA_OFFSET (2) #define WIL_EDMA_MAX_DATA_OFFSET (2)
/* RX buffer size must be aligned to 4 bytes */ /* RX buffer size must be aligned to 4 bytes */
#define WIL_EDMA_RX_BUF_LEN_DEFAULT (2048) #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, static void wil_tx_desc_unmap_edma(struct device *dev,
union wil_tx_desc *desc, union wil_tx_desc *desc,
...@@ -312,7 +313,8 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil, ...@@ -312,7 +313,8 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil,
struct list_head *free = &wil->rx_buff_mgmt.free; struct list_head *free = &wil->rx_buff_mgmt.free;
int i; 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); GFP_KERNEL);
if (!wil->rx_buff_mgmt.buff_arr) if (!wil->rx_buff_mgmt.buff_arr)
return -ENOMEM; return -ENOMEM;
...@@ -321,14 +323,16 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil, ...@@ -321,14 +323,16 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil,
INIT_LIST_HEAD(active); INIT_LIST_HEAD(active);
INIT_LIST_HEAD(free); 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; 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); list_add(&buff_arr[i].list, free);
buff_arr[i].id = i; buff_arr[i].id = i;
} }
wil->rx_buff_mgmt.size = size; wil->rx_buff_mgmt.size = size + 1;
return 0; return 0;
} }
...@@ -428,6 +432,9 @@ static void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring) ...@@ -428,6 +432,9 @@ static void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring)
&ring->pa, ring->ctx); &ring->pa, ring->ctx);
wil_move_all_rx_buff_to_free_list(wil, ring); 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; goto out;
} }
...@@ -804,18 +811,9 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil, ...@@ -804,18 +811,9 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil,
struct sk_buff *skb, struct sk_buff *skb,
struct wil_net_stats *stats) struct wil_net_stats *stats)
{ {
int error;
int l2_rx_status; int l2_rx_status;
int l3_rx_status;
int l4_rx_status;
void *msg = wil_skb_rxstatus(skb); 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); l2_rx_status = wil_rx_status_get_l2_rx_status(msg);
if (l2_rx_status != 0) { if (l2_rx_status != 0) {
wil_dbg_txrx(wil, "L2 RX error, l2_rx_status=0x%x\n", 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, ...@@ -844,17 +842,7 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil,
return -EFAULT; return -EFAULT;
} }
l3_rx_status = wil_rx_status_get_l3_rx_status(msg); skb->ip_summed = wil_rx_status_get_checksum(msg, stats);
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++;
return 0; return 0;
} }
...@@ -892,26 +880,50 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil, ...@@ -892,26 +880,50 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
/* Extract the buffer ID from the status message */ /* Extract the buffer ID from the status message */
buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg)); 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", wil_err(wil, "Corrupt buff_id=%d, sring->swhead=%d\n",
buff_id, sring->swhead); buff_id, sring->swhead);
wil_rx_status_reset_buff_id(sring);
wil_sring_advance_swhead(sring); wil_sring_advance_swhead(sring);
sring->invalid_buff_id_cnt++;
goto again; goto again;
} }
wil_sring_advance_swhead(sring);
/* Extract the SKB from the rx_buff management array */ /* Extract the SKB from the rx_buff management array */
skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL; wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
if (!skb) { if (!skb) {
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id); 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 */ /* Move the buffer from the active list to the free list */
list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list, list_move_tail(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
&wil->rx_buff_mgmt.free); &wil->rx_buff_mgmt.free);
wil_sring_advance_swhead(sring);
sring->invalid_buff_id_cnt++;
goto again; goto again;
} }
wil_rx_status_reset_buff_id(sring);
wil_sring_advance_swhead(sring);
memcpy(&pa, skb->cb, sizeof(pa)); memcpy(&pa, skb->cb, sizeof(pa));
dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
dmalen = le16_to_cpu(wil_rx_status_get_length(msg)); dmalen = le16_to_cpu(wil_rx_status_get_length(msg));
...@@ -926,8 +938,8 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil, ...@@ -926,8 +938,8 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
sizeof(struct wil_rx_status_extended), false); sizeof(struct wil_rx_status_extended), false);
/* Move the buffer from the active list to the free list */ /* Move the buffer from the active list to the free list */
list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list, list_move_tail(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
&wil->rx_buff_mgmt.free); &wil->rx_buff_mgmt.free);
eop = wil_rx_status_get_eop(msg); eop = wil_rx_status_get_eop(msg);
......
/* /*
* 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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 */ ...@@ -427,6 +427,12 @@ static inline int wil_rx_status_get_eop(void *msg) /* EoP = End of Packet */
30, 30); 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) static inline __le16 wil_rx_status_get_buff_id(void *msg)
{ {
return ((struct wil_rx_status_compressed *)msg)->buff_id; 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) ...@@ -511,6 +517,45 @@ static inline int wil_rx_status_get_l4_rx_status(void *msg)
5, 6); 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) static inline int wil_rx_status_get_security(void *msg)
{ {
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
......
...@@ -185,6 +185,7 @@ struct RGF_ICR { ...@@ -185,6 +185,7 @@ struct RGF_ICR {
/* registers - FW addresses */ /* registers - FW addresses */
#define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_1 (0x880004)
#define RGF_USER_USAGE_2 (0x880008)
#define RGF_USER_USAGE_6 (0x880018) #define RGF_USER_USAGE_6 (0x880018)
#define BIT_USER_OOB_MODE BIT(31) #define BIT_USER_OOB_MODE BIT(31)
#define BIT_USER_OOB_R2_MODE BIT(30) #define BIT_USER_OOB_R2_MODE BIT(30)
...@@ -367,6 +368,7 @@ struct RGF_ICR { ...@@ -367,6 +368,7 @@ struct RGF_ICR {
#define REVISION_ID_SPARROW_D0 (0x3) #define REVISION_ID_SPARROW_D0 (0x3)
#define RGF_OTP_MAC_TALYN_MB (0x8a0304) #define RGF_OTP_MAC_TALYN_MB (0x8a0304)
#define RGF_OTP_OEM_MAC (0x8a0334)
#define RGF_OTP_MAC (0x8a0620) #define RGF_OTP_MAC (0x8a0620)
/* Talyn-MB */ /* Talyn-MB */
...@@ -566,10 +568,11 @@ struct wil_status_ring { ...@@ -566,10 +568,11 @@ struct wil_status_ring {
bool is_rx; bool is_rx;
u8 desc_rdy_pol; /* Expected descriptor ready bit polarity */ u8 desc_rdy_pol; /* Expected descriptor ready bit polarity */
struct wil_ring_rx_data rx_data; struct wil_ring_rx_data rx_data;
u32 invalid_buff_id_cnt; /* relevant only for RX */
}; };
#define WIL_STA_TID_NUM (16) #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 { struct wil_net_stats {
unsigned long rx_packets; unsigned long rx_packets;
...@@ -660,7 +663,6 @@ enum { /* for wil6210_priv.status */ ...@@ -660,7 +663,6 @@ enum { /* for wil6210_priv.status */
wil_status_suspending, /* suspend in progress */ wil_status_suspending, /* suspend in progress */
wil_status_suspended, /* suspend completed, device is suspended */ wil_status_suspended, /* suspend completed, device is suspended */
wil_status_resuming, /* resume in progress */ wil_status_resuming, /* resume in progress */
wil_status_collecting_dumps, /* crashdump collection in progress */
wil_status_last /* keep last */ wil_status_last /* keep last */
}; };
...@@ -992,6 +994,8 @@ struct wil6210_priv { ...@@ -992,6 +994,8 @@ struct wil6210_priv {
struct wil_txrx_ops txrx_ops; struct wil_txrx_ops txrx_ops;
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ 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 */ /* statistics */
atomic_t isr_count_rx, isr_count_tx; atomic_t isr_count_rx, isr_count_tx;
/* debugfs */ /* debugfs */
...@@ -1060,6 +1064,7 @@ struct wil6210_priv { ...@@ -1060,6 +1064,7 @@ struct wil6210_priv {
#define vif_to_wil(v) (v->wil) #define vif_to_wil(v) (v->wil)
#define vif_to_ndev(v) (v->ndev) #define vif_to_ndev(v) (v->ndev)
#define vif_to_wdev(v) (&v->wdev) #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, static inline struct wil6210_vif *wdev_to_vif(struct wil6210_priv *wil,
struct wireless_dev *wdev) struct wireless_dev *wdev)
...@@ -1176,6 +1181,8 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, ...@@ -1176,6 +1181,8 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
size_t count); size_t count);
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count); size_t count);
int wil_mem_access_lock(struct wil6210_priv *wil);
void wil_mem_access_unlock(struct wil6210_priv *wil);
struct wil6210_vif * struct wil6210_vif *
wil_vif_alloc(struct wil6210_priv *wil, const char *name, wil_vif_alloc(struct wil6210_priv *wil, const char *name,
......
/* /*
* Copyright (c) 2015,2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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, ...@@ -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 wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
{ {
int i; int i, rc;
const struct fw_map *map; const struct fw_map *map;
void *data; void *data;
u32 host_min, dump_size, offset, len; 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) ...@@ -73,14 +73,9 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
return -EINVAL; return -EINVAL;
} }
set_bit(wil_status_collecting_dumps, wil->status); rc = wil_mem_access_lock(wil);
if (test_bit(wil_status_suspending, wil->status) || if (rc)
test_bit(wil_status_suspended, wil->status) || return rc;
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;
}
/* copy to crash dump area */ /* copy to crash dump area */
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { 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) ...@@ -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), wil_memcpy_fromio_32((void * __force)(dest + offset),
(const void __iomem * __force)data, len); (const void __iomem * __force)data, len);
} }
wil_mem_access_unlock(wil);
clear_bit(wil_status_collecting_dumps, wil->status);
return 0; return 0;
} }
......
...@@ -41,6 +41,7 @@ MODULE_PARM_DESC(led_id, ...@@ -41,6 +41,7 @@ MODULE_PARM_DESC(led_id,
#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200 #define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
#define WIL_WMI_CALL_GENERAL_TO_MS 100 #define WIL_WMI_CALL_GENERAL_TO_MS 100
#define WIL_WMI_PCP_STOP_TO_MS 5000
/** /**
* WMI event receiving - theory of operations * WMI event receiving - theory of operations
...@@ -2195,7 +2196,8 @@ int wmi_pcp_stop(struct wil6210_vif *vif) ...@@ -2195,7 +2196,8 @@ int wmi_pcp_stop(struct wil6210_vif *vif)
return rc; return rc;
return wmi_call(wil, WMI_PCP_STOP_CMDID, vif->mid, NULL, 0, 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) 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) ...@@ -2957,6 +2959,10 @@ static const char *suspend_status2name(u8 status)
switch (status) { switch (status) {
case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE: case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
return "LINK_NOT_IDLE"; return "LINK_NOT_IDLE";
case WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT:
return "DISCONNECT";
case WMI_TRAFFIC_SUSPEND_REJECTED_OTHER:
return "OTHER";
default: default:
return "Untracked status"; return "Untracked status";
} }
...@@ -3046,6 +3052,9 @@ static void resume_triggers2string(u32 triggers, char *string, int str_size) ...@@ -3046,6 +3052,9 @@ static void resume_triggers2string(u32 triggers, char *string, int str_size)
if (triggers & WMI_RESUME_TRIGGER_WMI_EVT) if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
strlcat(string, " WMI_EVT", str_size); strlcat(string, " WMI_EVT", str_size);
if (triggers & WMI_RESUME_TRIGGER_DISCONNECT)
strlcat(string, " DISCONNECT", str_size);
} }
int wmi_resume(struct wil6210_priv *wil) int wmi_resume(struct wil6210_priv *wil)
...@@ -3196,7 +3205,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, ...@@ -3196,7 +3205,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
if (mid == MID_BROADCAST) if (mid == MID_BROADCAST)
mid = 0; 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", wil_dbg_wmi(wil, "invalid mid %d, event skipped\n",
mid); mid);
return; return;
...@@ -3502,8 +3511,9 @@ int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len) ...@@ -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, rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, vif->mid, cmd, total,
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) { if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "mgmt_tx failed with status %d\n", evt.evt.status); wil_dbg_wmi(wil, "mgmt_tx failed with status %d\n",
rc = -EINVAL; evt.evt.status);
rc = -EAGAIN;
} }
kfree(cmd); kfree(cmd);
...@@ -3555,9 +3565,9 @@ int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len, ...@@ -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, rc = wmi_call(wil, WMI_SW_TX_REQ_EXT_CMDID, vif->mid, cmd, total,
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) { if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "mgmt_tx_ext failed with status %d\n", wil_dbg_wmi(wil, "mgmt_tx_ext failed with status %d\n",
evt.evt.status); evt.evt.status);
rc = -EINVAL; rc = -EAGAIN;
} }
kfree(cmd); kfree(cmd);
......
/* /*
* 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) 2012-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity * Copyright (c) 2006-2012 Wilocity
* *
...@@ -104,6 +104,7 @@ enum wmi_fw_capability { ...@@ -104,6 +104,7 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_RAW_MODE = 24, WMI_FW_CAPABILITY_RAW_MODE = 24,
WMI_FW_CAPABILITY_TX_REQ_EXT = 25, WMI_FW_CAPABILITY_TX_REQ_EXT = 25,
WMI_FW_CAPABILITY_CHANNEL_4 = 26, WMI_FW_CAPABILITY_CHANNEL_4 = 26,
WMI_FW_CAPABILITY_IPA = 27,
WMI_FW_CAPABILITY_MAX, WMI_FW_CAPABILITY_MAX,
}; };
...@@ -294,6 +295,7 @@ enum wmi_command_id { ...@@ -294,6 +295,7 @@ enum wmi_command_id {
WMI_SET_AP_SLOT_SIZE_CMDID = 0xA0F, WMI_SET_AP_SLOT_SIZE_CMDID = 0xA0F,
WMI_SET_VRING_PRIORITY_WEIGHT_CMDID = 0xA10, WMI_SET_VRING_PRIORITY_WEIGHT_CMDID = 0xA10,
WMI_SET_VRING_PRIORITY_CMDID = 0xA11, WMI_SET_VRING_PRIORITY_CMDID = 0xA11,
WMI_RBUFCAP_CFG_CMDID = 0xA12,
WMI_SET_MAC_ADDRESS_CMDID = 0xF003, WMI_SET_MAC_ADDRESS_CMDID = 0xF003,
WMI_ABORT_SCAN_CMDID = 0xF007, WMI_ABORT_SCAN_CMDID = 0xF007,
WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041,
...@@ -979,10 +981,22 @@ enum wmi_rx_msg_type { ...@@ -979,10 +981,22 @@ enum wmi_rx_msg_type {
WMI_RX_MSG_TYPE_EXTENDED = 0x01, 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_tx_status_ring_add_cmd {
struct wmi_edma_ring_cfg ring_cfg; struct wmi_edma_ring_cfg ring_cfg;
u8 irq_index; u8 irq_index;
u8 reserved[3]; /* wmi_ring_add_irq_mode */
u8 irq_mode;
u8 reserved[2];
} __packed; } __packed;
struct wmi_rx_status_ring_add_cmd { struct wmi_rx_status_ring_add_cmd {
...@@ -1016,7 +1030,10 @@ struct wmi_tx_desc_ring_add_cmd { ...@@ -1016,7 +1030,10 @@ struct wmi_tx_desc_ring_add_cmd {
u8 mac_ctrl; u8 mac_ctrl;
u8 to_resolution; u8 to_resolution;
u8 agg_max_wsize; 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; struct wmi_vring_cfg_schd schd_params;
} __packed; } __packed;
...@@ -1982,6 +1999,7 @@ enum wmi_event_id { ...@@ -1982,6 +1999,7 @@ enum wmi_event_id {
WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836, WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836,
WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
WMI_BF_TRIG_EVENTID = 0x183A,
WMI_RS_MGMT_DONE_EVENTID = 0x1852, WMI_RS_MGMT_DONE_EVENTID = 0x1852,
WMI_RF_MGMT_STATUS_EVENTID = 0x1853, WMI_RF_MGMT_STATUS_EVENTID = 0x1853,
WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838,
...@@ -2082,6 +2100,7 @@ enum wmi_event_id { ...@@ -2082,6 +2100,7 @@ enum wmi_event_id {
WMI_SET_AP_SLOT_SIZE_EVENTID = 0x1A0F, WMI_SET_AP_SLOT_SIZE_EVENTID = 0x1A0F,
WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID = 0x1A10, WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID = 0x1A10,
WMI_SET_VRING_PRIORITY_EVENTID = 0x1A11, WMI_SET_VRING_PRIORITY_EVENTID = 0x1A11,
WMI_RBUFCAP_CFG_EVENTID = 0x1A12,
WMI_SET_CHANNEL_EVENTID = 0x9000, WMI_SET_CHANNEL_EVENTID = 0x9000,
WMI_ASSOC_REQ_EVENTID = 0x9001, WMI_ASSOC_REQ_EVENTID = 0x9001,
WMI_EAPOL_RX_EVENTID = 0x9002, WMI_EAPOL_RX_EVENTID = 0x9002,
...@@ -2267,7 +2286,9 @@ struct wmi_notify_req_done_event { ...@@ -2267,7 +2286,9 @@ struct wmi_notify_req_done_event {
__le32 status; __le32 status;
__le64 tsf; __le64 tsf;
s8 rssi; s8 rssi;
u8 reserved0[3]; /* enum wmi_edmg_tx_mode */
u8 tx_mode;
u8 reserved0[2];
__le32 tx_tpt; __le32 tx_tpt;
__le32 tx_goodput; __le32 tx_goodput;
__le32 rx_goodput; __le32 rx_goodput;
...@@ -2316,6 +2337,7 @@ enum wmi_disconnect_reason { ...@@ -2316,6 +2337,7 @@ enum wmi_disconnect_reason {
WMI_DIS_REASON_PROFILE_MISMATCH = 0x0C, WMI_DIS_REASON_PROFILE_MISMATCH = 0x0C,
WMI_DIS_REASON_CONNECTION_EVICTED = 0x0D, WMI_DIS_REASON_CONNECTION_EVICTED = 0x0D,
WMI_DIS_REASON_IBSS_MERGE = 0x0E, WMI_DIS_REASON_IBSS_MERGE = 0x0E,
WMI_DIS_REASON_HIGH_TEMPERATURE = 0x0F,
}; };
/* WMI_DISCONNECT_EVENTID */ /* WMI_DISCONNECT_EVENTID */
...@@ -3168,6 +3190,30 @@ struct wmi_brp_set_ant_limit_event { ...@@ -3168,6 +3190,30 @@ struct wmi_brp_set_ant_limit_event {
u8 reserved[3]; u8 reserved[3];
} __packed; } __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 */ /* broadcast connection ID */
#define WMI_LINK_MAINTAIN_CFG_CID_BROADCAST (0xFFFFFFFF) #define WMI_LINK_MAINTAIN_CFG_CID_BROADCAST (0xFFFFFFFF)
...@@ -3263,6 +3309,8 @@ struct wmi_link_maintain_cfg_read_done_event { ...@@ -3263,6 +3309,8 @@ struct wmi_link_maintain_cfg_read_done_event {
enum wmi_traffic_suspend_status { enum wmi_traffic_suspend_status {
WMI_TRAFFIC_SUSPEND_APPROVED = 0x0, WMI_TRAFFIC_SUSPEND_APPROVED = 0x0,
WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE = 0x1, WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE = 0x1,
WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT = 0x2,
WMI_TRAFFIC_SUSPEND_REJECTED_OTHER = 0x3,
}; };
/* WMI_TRAFFIC_SUSPEND_EVENTID */ /* WMI_TRAFFIC_SUSPEND_EVENTID */
...@@ -3282,6 +3330,7 @@ enum wmi_resume_trigger { ...@@ -3282,6 +3330,7 @@ enum wmi_resume_trigger {
WMI_RESUME_TRIGGER_UCAST_RX = 0x2, WMI_RESUME_TRIGGER_UCAST_RX = 0x2,
WMI_RESUME_TRIGGER_BCAST_RX = 0x4, WMI_RESUME_TRIGGER_BCAST_RX = 0x4,
WMI_RESUME_TRIGGER_WMI_EVT = 0x8, WMI_RESUME_TRIGGER_WMI_EVT = 0x8,
WMI_RESUME_TRIGGER_DISCONNECT = 0x10,
}; };
/* WMI_TRAFFIC_RESUME_EVENTID */ /* WMI_TRAFFIC_RESUME_EVENTID */
...@@ -4057,4 +4106,38 @@ struct wmi_set_vring_priority_event { ...@@ -4057,4 +4106,38 @@ struct wmi_set_vring_priority_event {
u8 reserved[3]; u8 reserved[3];
} __packed; } __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__ */ #endif /* __WILOCITY_WMI_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment