From 73a7d1e34d889ee4b23ac0698bd924e5ef63969c Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Thu, 28 Feb 2019 11:34:42 +0200 Subject: wil6210: align to latest auto generated wmi.h Align to latest version of the auto generated wmi file describing the interface with FW. Signed-off-by: Alexei Avshalom Lazar Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 7 +++ drivers/net/wireless/ath/wil6210/wmi.h | 91 ++++++++++++++++++++++++++++++++-- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index bda4a9712f91..c737a79e1541 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -2957,6 +2957,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 +3050,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) 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__ */ -- cgit v1.2.3 From a061894587ef61d19e5196c601ac250cc19f406f Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Thu, 28 Feb 2019 11:34:44 +0200 Subject: wil6210: prevent device memory access while in reset or suspend Accessing some of the memory of the device while the device is resetting or suspending may cause unexpected error as the HW is still not in a stable state. Prevent this access to guarantee successful read/write memory operations. Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 25 +++++++++++--- drivers/net/wireless/ath/wil6210/main.c | 41 +++++++++++++++++------ drivers/net/wireless/ath/wil6210/pm.c | 29 ++++++++++------ drivers/net/wireless/ath/wil6210/wil6210.h | 5 ++- drivers/net/wireless/ath/wil6210/wil_crash_dump.c | 18 ++++------ 5 files changed, 80 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 7ad4e5328439..27cb182ae423 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -258,6 +258,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 +328,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 +607,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 +620,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 +639,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 +665,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); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 277abfdf3322..6df19a2a6ce7 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]; @@ -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) @@ -1599,15 +1622,6 @@ 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); @@ -1782,7 +1796,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 +1870,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 +1890,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/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 75fe9323547c..f307522fa26d 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 @@ -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/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index e1b1039b13ab..c4176323aab5 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -660,7 +660,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 +991,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 */ @@ -1176,6 +1177,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; } -- cgit v1.2.3 From 5793fe9d4fde6897dbf821444ab57c45cb0a10db Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 28 Feb 2019 11:34:46 +0200 Subject: wil6210: increase PCP stop command timeout In case there are connected stations, FW needs to disconnect them before handling PCP stop. This flow can take several seconds. Increasing PCP stop timeout to 5 seconds to allow that. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c737a79e1541..19247c51908d 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) -- cgit v1.2.3 From f6194f769dfce79cb3084086118e0cea056e8676 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 28 Feb 2019 11:34:48 +0200 Subject: wil6210: do not set BIT_USER_SUPPORT_T_POWER_ON_0 in Talyn-MB In Sparrow, FW might sleep long time due to T_Power_On calculation in slow clock, so T_Power_On was set to zero to shorten the L1SS wake-up time. In Talyn-MB the L1SS wake-up procedure is handled by the PMU (HW), hence T_Power_On calculation is accurate and should not be forced to zero. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6df19a2a6ce7..f2432adeec3e 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1603,7 +1603,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); } -- cgit v1.2.3 From 044974fbeadee4a5c0554ee7d83d22495ad3d450 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 28 Feb 2019 11:34:50 +0200 Subject: wil6210: update WIL_MCS_MAX to 15 Update max MCS to 15, which is supported by Talyn-MB. This will allow collecting statistics on number of RX packets in higher MCS. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wil6210.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c4176323aab5..1b81f3fd59a0 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -569,7 +569,7 @@ struct wil_status_ring { }; #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; -- cgit v1.2.3 From e4a29bdd8f82627d88644971235dc12b70c4150b Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Thu, 28 Feb 2019 11:34:52 +0200 Subject: wil6210: check mid is valid Check that the mid is valid and that it does not exceed the memory size allocated to vifs array. Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 6 +++--- drivers/net/wireless/ath/wil6210/debugfs.c | 10 +++++----- drivers/net/wireless/ath/wil6210/main.c | 8 ++++---- drivers/net/wireless/ath/wil6210/netdev.c | 10 +++++----- drivers/net/wireless/ath/wil6210/pcie_bus.c | 4 ++-- drivers/net/wireless/ath/wil6210/pm.c | 6 +++--- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index a1e226652b4a..e8d65ddb1b0a 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) { @@ -1806,7 +1806,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 = {}; diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 27cb182ae423..817762f58994 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1381,7 +1381,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) @@ -1579,7 +1579,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 && @@ -1645,7 +1645,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) { @@ -1866,7 +1866,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); @@ -1922,7 +1922,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; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index f2432adeec3e..6a6bfb3b25ca 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -685,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); @@ -1483,7 +1483,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) @@ -1551,7 +1551,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; @@ -1627,7 +1627,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) 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); 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 f307522fa26d..56143e7670ed 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -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) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 1b81f3fd59a0..de724666857f 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1061,6 +1061,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) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 19247c51908d..c5bcb8da07c1 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -3205,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; -- cgit v1.2.3 From 7b834639c4c4cbb19acb0842a8f4ee11ea079c6f Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Thu, 28 Feb 2019 11:34:54 +0200 Subject: wil6210: use OEM MAC address from OTP In addition to existing MAC address field in OTP, new field added for OEM MAC address. wil6210 gives precedence to the new OEM MAC address and will use it if its valid. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 21 +++++++++++++++------ drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6a6bfb3b25ca..b69d9a21e618 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1413,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; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index de724666857f..9d7e02e6c3aa 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -367,6 +367,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 */ -- cgit v1.2.3 From 29ca376066df05760a7d7038a95aba1c3b968e9e Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Thu, 28 Feb 2019 11:34:57 +0200 Subject: wil6210: free edma_rx_swtail upon reset edma_rx_swtail dma memory free is missing. Add this part of Rx desc ring free. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx_edma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index c38773878ae3..48098ae62677 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -428,6 +428,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; } -- cgit v1.2.3 From 4bf019865cf327df2fed403d35bb36ecb6617e8a Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Thu, 28 Feb 2019 11:34:59 +0200 Subject: wil6210: fix report of rx packet checksum in edma mode Update the rx packet checksum of received packet according to edma HW spec: No need to calculate checksum in the following cases: L4_status=0 and L3_status=0 - No L3 and no L4 known protocols found L4_status=0 and L3_status=1 - L3 was found, and checksum check passed. No known L4 protocol was found. L4_status=1 - L4 was found, and checksum check passed. Recalculate checksum in the following cases: L4_status=3 and L3_status=1 - It means that L3 protocol was found, and checksum passed, but L4 checksum failed. L4_status=3 and L3_status=2 - Both L3 and L4 checksum check failed. Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx_edma.c | 21 +------------- drivers/net/wireless/ath/wil6210/txrx_edma.h | 41 +++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 48098ae62677..492f7bdf39d9 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -807,18 +807,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", @@ -847,17 +838,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; } diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index 343516a03a1e..9cf9ecf6e8cf 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 @@ -511,6 +511,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, -- cgit v1.2.3 From 49122ec42634f73babb1dc96f170023e5228d080 Mon Sep 17 00:00:00 2001 From: Lior David Date: Thu, 28 Feb 2019 11:35:01 +0200 Subject: wil6210: fix return code of wmi_mgmt_tx and wmi_mgmt_tx_ext The functions that send management TX frame have 3 possible results: success and other side acknowledged receive (ACK=1), success and other side did not acknowledge receive(ACK=0) and failure to send the frame. The current implementation incorrectly reports the ACK=0 case as failure. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 5 +++++ drivers/net/wireless/ath/wil6210/wmi.c | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index e8d65ddb1b0a..218296e319b9 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -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); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c5bcb8da07c1..d89cd41e78ac 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -3511,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); @@ -3564,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); -- cgit v1.2.3 From 1683a001d5bf244bc6d9751d0b50ec382006ec27 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 28 Feb 2019 11:35:03 +0200 Subject: wil6210: prevent access to RGF_CAF_ICR in Talyn Due to access control RGF_CAF_ICR cannot be accessed by host. Such an access will cause device AHB logger to halt and it will not capture future AHB fault if there is any. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index b69d9a21e618..9b9c9ec01536 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1532,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 -- cgit v1.2.3 From 8454e72a3644c7f3617ed85be899291f344dba7f Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Thu, 28 Feb 2019 11:35:05 +0200 Subject: wil6210: add support for ucode tracing The driver needs to expose RGF_USER_USAGE_2 register that contains the offset of the ucode logging table. Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 1 + drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 817762f58994..78320ec125c4 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -2392,6 +2392,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/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9d7e02e6c3aa..f508d52c867a 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) -- cgit v1.2.3 From b4a967b7d0f5cee75cfa343b7498eb92a8735594 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 28 Feb 2019 11:35:08 +0200 Subject: wil6210: reset buff id in status message after completion Since DR bit and buffer id are written in different dwords of the status message, the DR bit can already be set to 1 while the buffer id is not updated yet. Resetting the buffer id in the status message will allow the driver to identify such cases and re-read the status message until the buffer id is written by HW. In case DR bit is set but buffer id is zero, need to read the status message again, until a valid id is identified. In addition to that, move the completed buffer id to the tail of the free list to prevent its immediate reuse in the upcoming refill. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 ++ drivers/net/wireless/ath/wil6210/txrx_edma.c | 50 ++++++++++++++++++++++------ drivers/net/wireless/ath/wil6210/txrx_edma.h | 6 ++++ drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 78320ec125c4..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; diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 492f7bdf39d9..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; } @@ -876,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)); @@ -910,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 9cf9ecf6e8cf..bb4ff28b73e5 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -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; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f508d52c867a..8724d9975606 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -568,6 +568,7 @@ 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) -- cgit v1.2.3 From fa0b735414f90bbd08637630dbad5cb1278dd661 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 28 Feb 2019 11:35:10 +0200 Subject: wil6210: print error in FW and board files load failures Add an error print-out in case FW and board files load fails, as such an error is not printed on all failures and user may not understand why the interface up operations didn't succeed. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/fw_inc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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; } -- cgit v1.2.3