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,
.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 = {};
......
......@@ -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},
{},
};
......
/*
* 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;
}
......
......@@ -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)
......
/*
* 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;
}
......
/*
* 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);
......
/*
* 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);
......
......@@ -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 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
/* 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 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
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);
......
/*
* 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,
......
......@@ -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,
......
/*
* 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;
}
......
......@@ -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);
......
/*
* 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__ */
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