blob: d90fe1c0ec62dac40cfb590b54ac60d1c5fa001d [file] [log] [blame]
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001/*
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +02002 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080017#include <linux/moduleparam.h>
18#include <linux/if_arp.h>
Vladimir Kondratiev108d1eb2014-02-27 16:20:53 +020019#include <linux/etherdevice.h>
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080020
21#include "wil6210.h"
Vladimir Kondratievb4490f42014-02-27 16:20:44 +020022#include "txrx.h"
Dedy Lanskyf172b562014-09-10 16:34:38 +030023#include "wmi.h"
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +030024#include "boot_loader.h"
Dedy Lanskyf172b562014-09-10 16:34:38 +030025
Maya Erez349214c2016-04-26 14:41:41 +030026#define WAIT_FOR_HALP_VOTE_MS 100
Maya Erez4cbb5852017-02-16 15:26:09 +020027#define WAIT_FOR_SCAN_ABORT_MS 1000
Maya Erez349214c2016-04-26 14:41:41 +030028
Vladimir Kondratievbfc2dc72015-03-30 11:28:50 +030029bool debug_fw; /* = false; */
Maya Erezc2256ec2017-02-08 13:18:42 +020030module_param(debug_fw, bool, 0444);
Vladimir Kondratievbfc2dc72015-03-30 11:28:50 +030031MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
32
Lior David42ce0aa2017-03-27 21:42:25 +030033static u8 oob_mode;
34module_param(oob_mode, byte, 0444);
Lior David1f1a3612016-03-01 19:18:18 +020035MODULE_PARM_DESC(oob_mode,
36 " enable out of the box (OOB) mode in FW, for diagnostics and certification");
37
Vladimir Kondratievc33407a2014-10-01 15:05:24 +030038bool no_fw_recovery;
Maya Erezc2256ec2017-02-08 13:18:42 +020039module_param(no_fw_recovery, bool, 0644);
Vladimir Kondratievc33407a2014-10-01 15:05:24 +030040MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +020041
Vladimir Kondratievab954622014-12-23 09:47:20 +020042/* if not set via modparam, will be set to default value of 1/8 of
43 * rx ring size during init flow
44 */
45unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT;
Maya Erezc2256ec2017-02-08 13:18:42 +020046module_param(rx_ring_overflow_thrsh, ushort, 0444);
Vladimir Kondratievab954622014-12-23 09:47:20 +020047MODULE_PARM_DESC(rx_ring_overflow_thrsh,
48 " RX ring overflow threshold in descriptors.");
Vladimir Kondratievb6b1b0e2014-09-22 15:31:41 +030049
Vladimir Kondratiev9a06bec2014-10-28 16:51:27 +020050/* We allow allocation of more than 1 page buffers to support large packets.
51 * It is suboptimal behavior performance wise in case MTU above page size.
52 */
Vladimir Kondratievc44690a2014-12-23 09:47:11 +020053unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
Vladimir Kondratiev9a06bec2014-10-28 16:51:27 +020054static int mtu_max_set(const char *val, const struct kernel_param *kp)
55{
56 int ret;
57
58 /* sets mtu_max directly. no need to restore it in case of
59 * illegal value since we assume this will fail insmod
60 */
61 ret = param_set_uint(val, kp);
62 if (ret)
63 return ret;
64
Vladimir Kondratiev4590d812014-12-23 09:47:12 +020065 if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
Vladimir Kondratiev9a06bec2014-10-28 16:51:27 +020066 ret = -EINVAL;
67
68 return ret;
69}
70
Luis R. Rodriguez9c278472015-05-27 11:09:38 +093071static const struct kernel_param_ops mtu_max_ops = {
Vladimir Kondratiev9a06bec2014-10-28 16:51:27 +020072 .set = mtu_max_set,
73 .get = param_get_uint,
74};
75
Maya Erezc2256ec2017-02-08 13:18:42 +020076module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444);
Vladimir Kondratiev9a06bec2014-10-28 16:51:27 +020077MODULE_PARM_DESC(mtu_max, " Max MTU value.");
78
Vladimir Kondratievd3762b42014-12-01 15:35:02 +020079static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
80static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
Vladimir Kondratiev41d6b092015-03-15 16:00:23 +020081static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
Vladimir Kondratievd3762b42014-12-01 15:35:02 +020082
83static int ring_order_set(const char *val, const struct kernel_param *kp)
84{
85 int ret;
86 uint x;
87
88 ret = kstrtouint(val, 0, &x);
89 if (ret)
90 return ret;
91
92 if ((x < WIL_RING_SIZE_ORDER_MIN) || (x > WIL_RING_SIZE_ORDER_MAX))
93 return -EINVAL;
94
95 *((uint *)kp->arg) = x;
96
97 return 0;
98}
99
Luis R. Rodriguez9c278472015-05-27 11:09:38 +0930100static const struct kernel_param_ops ring_order_ops = {
Vladimir Kondratievd3762b42014-12-01 15:35:02 +0200101 .set = ring_order_set,
102 .get = param_get_uint,
103};
104
Maya Erezc2256ec2017-02-08 13:18:42 +0200105module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, 0444);
Vladimir Kondratievd3762b42014-12-01 15:35:02 +0200106MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
Maya Erezc2256ec2017-02-08 13:18:42 +0200107module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, 0444);
Vladimir Kondratievd3762b42014-12-01 15:35:02 +0200108MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
Maya Erezc2256ec2017-02-08 13:18:42 +0200109module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, 0444);
Vladimir Kondratievd507d1b2015-06-09 14:11:17 +0300110MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order");
Vladimir Kondratievd3762b42014-12-01 15:35:02 +0200111
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300112#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
113#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
114
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800115/*
116 * Due to a hardware issue,
117 * one has to read/write to/from NIC in 32-bit chunks;
118 * regular memcpy_fromio and siblings will
119 * not work on 64-bit platform - it uses 64-bit transactions
120 *
121 * Force 32-bit transactions to enable NIC on 64-bit platforms
122 *
123 * To avoid byte swap on big endian host, __raw_{read|write}l
124 * should be used - {read|write}l would swap bytes to provide
125 * little endian on PCI value in host endianness.
126 */
127void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
128 size_t count)
129{
130 u32 *d = dst;
131 const volatile u32 __iomem *s = src;
132
Dedy Lansky82047212017-03-28 21:25:42 +0300133 for (; count >= 4; count -= 4)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800134 *d++ = __raw_readl(s++);
Dedy Lansky82047212017-03-28 21:25:42 +0300135
136 if (unlikely(count)) {
137 /* count can be 1..3 */
138 u32 tmp = __raw_readl(s);
139
140 memcpy(d, &tmp, count);
141 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800142}
143
144void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
145 size_t count)
146{
147 volatile u32 __iomem *d = dst;
148 const u32 *s = src;
149
Dedy Lansky82047212017-03-28 21:25:42 +0300150 for (; count >= 4; count -= 4)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800151 __raw_writel(*s++, d++);
Dedy Lansky82047212017-03-28 21:25:42 +0300152
153 if (unlikely(count)) {
154 /* count can be 1..3 */
155 u32 tmp = 0;
156
157 memcpy(&tmp, s, count);
158 __raw_writel(tmp, d);
159 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800160}
161
Vladimir Kondratievb516fcc2014-10-28 16:50:08 +0200162static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200163 u16 reason_code, bool from_event)
Vladimir Kondratievbd332732014-12-23 09:47:24 +0200164__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200165{
166 uint i;
Vladimir Kondratievfc58f682014-06-16 19:37:16 +0300167 struct net_device *ndev = wil_to_ndev(wil);
168 struct wireless_dev *wdev = wil->wdev;
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200169 struct wil_sta_info *sta = &wil->sta[cid];
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +0300170
Vladimir Kondratievbd332732014-12-23 09:47:24 +0200171 might_sleep();
Lazar Alexei3190cc62017-02-23 14:34:14 +0200172 wil_dbg_misc(wil, "disconnect_cid: CID %d, status %d\n",
173 cid, sta->status);
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200174 /* inform upper/lower layers */
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +0200175 if (sta->status != wil_sta_unused) {
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +0200176 if (!from_event) {
177 bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
178 disable_ap_sme : false;
179 wmi_disconnect_sta(wil, sta->addr, reason_code,
180 true, del_sta);
181 }
Vladimir Kondratievb516fcc2014-10-28 16:50:08 +0200182
Vladimir Kondratievfc58f682014-06-16 19:37:16 +0300183 switch (wdev->iftype) {
184 case NL80211_IFTYPE_AP:
185 case NL80211_IFTYPE_P2P_GO:
186 /* AP-like interface */
187 cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL);
188 break;
189 default:
190 break;
191 }
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +0200192 sta->status = wil_sta_unused;
Hamad Kadmany105dd0f2017-04-04 15:14:17 +0300193 sta->fst_link_loss = false;
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +0200194 }
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200195 /* reorder buffers */
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200196 for (i = 0; i < WIL_STA_TID_NUM; i++) {
Dedy Lanskyec81b5a2014-09-10 16:34:42 +0300197 struct wil_tid_ampdu_rx *r;
Dedy Lanskyec81b5a2014-09-10 16:34:42 +0300198
Vladimir Kondratievbd332732014-12-23 09:47:24 +0200199 spin_lock_bh(&sta->tid_rx_lock);
Dedy Lanskyec81b5a2014-09-10 16:34:42 +0300200
201 r = sta->tid_rx[i];
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200202 sta->tid_rx[i] = NULL;
203 wil_tid_ampdu_rx_free(wil, r);
Dedy Lanskyec81b5a2014-09-10 16:34:42 +0300204
Vladimir Kondratievbd332732014-12-23 09:47:24 +0200205 spin_unlock_bh(&sta->tid_rx_lock);
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200206 }
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200207 /* crypto context */
208 memset(sta->tid_crypto_rx, 0, sizeof(sta->tid_crypto_rx));
209 memset(&sta->group_crypto_rx, 0, sizeof(sta->group_crypto_rx));
210 /* release vrings */
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200211 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
212 if (wil->vring2cid_tid[i][0] == cid)
213 wil_vring_fini_tx(wil, i);
214 }
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200215 /* statistics */
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200216 memset(&sta->stats, 0, sizeof(sta->stats));
217}
218
Dedy Lansky970a98f2016-12-06 08:26:49 +0200219static bool wil_is_connected(struct wil6210_priv *wil)
Maya Erez54eaa8c2016-04-26 14:41:40 +0300220{
221 int i;
222
223 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
224 if (wil->sta[i].status == wil_sta_connected)
225 return true;
226 }
227
228 return false;
229}
230
Vladimir Kondratievb516fcc2014-10-28 16:50:08 +0200231static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200232 u16 reason_code, bool from_event)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800233{
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200234 int cid = -ENOENT;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800235 struct net_device *ndev = wil_to_ndev(wil);
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200236 struct wireless_dev *wdev = wil->wdev;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800237
Lior David2690c4c2016-08-18 16:52:16 +0300238 if (unlikely(!ndev))
239 return;
240
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200241 might_sleep();
Lazar Alexei3190cc62017-02-23 14:34:14 +0200242 wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid,
Maya Erez0916d9f2016-01-17 12:39:10 +0200243 reason_code, from_event ? "+" : "-");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800244
Vladimir Kondratiev100106d2014-12-23 09:47:07 +0200245 /* Cases are:
246 * - disconnect single STA, still connected
247 * - disconnect single STA, already disconnected
248 * - disconnect all
249 *
Vladimir Kondratiev68682b42015-10-04 10:23:22 +0300250 * For "disconnect all", there are 3 options:
Vladimir Kondratiev100106d2014-12-23 09:47:07 +0200251 * - bssid == NULL
Vladimir Kondratiev68682b42015-10-04 10:23:22 +0300252 * - bssid is broadcast address (ff:ff:ff:ff:ff:ff)
Vladimir Kondratiev100106d2014-12-23 09:47:07 +0200253 * - bssid is our MAC address
254 */
Vladimir Kondratiev68682b42015-10-04 10:23:22 +0300255 if (bssid && !is_broadcast_ether_addr(bssid) &&
256 !ether_addr_equal_unaligned(ndev->dev_addr, bssid)) {
Vladimir Kondratiev100106d2014-12-23 09:47:07 +0200257 cid = wil_find_cid(wil, bssid);
258 wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
259 bssid, cid, reason_code);
260 if (cid >= 0) /* disconnect 1 peer */
261 wil_disconnect_cid(wil, cid, reason_code, from_event);
262 } else { /* all */
263 wil_dbg_misc(wil, "Disconnect all\n");
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200264 for (cid = 0; cid < WIL6210_MAX_CID; cid++)
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200265 wil_disconnect_cid(wil, cid, reason_code, from_event);
Vladimir Kondratiev100106d2014-12-23 09:47:07 +0200266 }
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200267
268 /* link state */
269 switch (wdev->iftype) {
270 case NL80211_IFTYPE_STATION:
271 case NL80211_IFTYPE_P2P_CLIENT:
Vladimir Kondratiev41d6b092015-03-15 16:00:23 +0200272 wil_bcast_fini(wil);
Dedy Lansky970a98f2016-12-06 08:26:49 +0200273 wil_update_net_queues_bh(wil, NULL, true);
Dedy Lanskyc5e96c92015-01-25 10:52:43 +0200274 netif_carrier_off(ndev);
Lior David704099f2017-05-04 21:31:02 +0300275 wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
Dedy Lanskyc5e96c92015-01-25 10:52:43 +0200276
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200277 if (test_bit(wil_status_fwconnected, wil->status)) {
278 clear_bit(wil_status_fwconnected, wil->status);
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200279 cfg80211_disconnected(ndev, reason_code,
Dedy Lansky0a4e9d12017-03-27 21:21:31 +0300280 NULL, 0,
281 wil->locally_generated_disc,
282 GFP_KERNEL);
283 wil->locally_generated_disc = false;
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200284 } else if (test_bit(wil_status_fwconnecting, wil->status)) {
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200285 cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
286 WLAN_STATUS_UNSPECIFIED_FAILURE,
287 GFP_KERNEL);
Dedy Lanskya4882782017-05-04 21:36:09 +0300288 wil->bss = NULL;
Vladimir Kondratievb4490f42014-02-27 16:20:44 +0200289 }
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200290 clear_bit(wil_status_fwconnecting, wil->status);
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200291 break;
Maya Erez54eaa8c2016-04-26 14:41:40 +0300292 case NL80211_IFTYPE_AP:
293 case NL80211_IFTYPE_P2P_GO:
Dedy Lansky970a98f2016-12-06 08:26:49 +0200294 if (!wil_is_connected(wil)) {
295 wil_update_net_queues_bh(wil, NULL, true);
Maya Erez54eaa8c2016-04-26 14:41:40 +0300296 clear_bit(wil_status_fwconnected, wil->status);
Dedy Lansky970a98f2016-12-06 08:26:49 +0200297 } else {
298 wil_update_net_queues_bh(wil, NULL, false);
299 }
Maya Erez54eaa8c2016-04-26 14:41:40 +0300300 break;
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200301 default:
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200302 break;
Vladimir Kondratievb4490f42014-02-27 16:20:44 +0200303 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800304}
305
306static void wil_disconnect_worker(struct work_struct *work)
307{
308 struct wil6210_priv *wil = container_of(work,
309 struct wil6210_priv, disconnect_worker);
Dedy Lansky19eddc62017-03-27 21:20:08 +0300310 struct net_device *ndev = wil_to_ndev(wil);
311 int rc;
312 struct {
313 struct wmi_cmd_hdr wmi;
314 struct wmi_disconnect_event evt;
315 } __packed reply;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800316
Dedy Lansky19eddc62017-03-27 21:20:08 +0300317 if (test_bit(wil_status_fwconnected, wil->status))
318 /* connect succeeded after all */
319 return;
320
321 if (!test_bit(wil_status_fwconnecting, wil->status))
322 /* already disconnected */
323 return;
324
325 rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
326 WMI_DISCONNECT_EVENTID, &reply, sizeof(reply),
327 WIL6210_DISCONNECT_TO_MS);
328 if (rc) {
329 wil_err(wil, "disconnect error %d\n", rc);
330 return;
331 }
332
333 wil_update_net_queues_bh(wil, NULL, true);
334 netif_carrier_off(ndev);
335 cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
336 WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
337 clear_bit(wil_status_fwconnecting, wil->status);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800338}
339
340static void wil_connect_timer_fn(ulong x)
341{
342 struct wil6210_priv *wil = (void *)x;
Maya Erez0916d9f2016-01-17 12:39:10 +0200343 bool q;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800344
Maya Erez0916d9f2016-01-17 12:39:10 +0200345 wil_err(wil, "Connect timeout detected, disconnect station\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800346
347 /* reschedule to thread context - disconnect won't
Maya Erez0916d9f2016-01-17 12:39:10 +0200348 * run from atomic context.
349 * queue on wmi_wq to prevent race with connect event.
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800350 */
Maya Erez0916d9f2016-01-17 12:39:10 +0200351 q = queue_work(wil->wmi_wq, &wil->disconnect_worker);
352 wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800353}
354
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300355static void wil_scan_timer_fn(ulong x)
356{
357 struct wil6210_priv *wil = (void *)x;
358
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200359 clear_bit(wil_status_fwready, wil->status);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300360 wil_err(wil, "Scan timeout detected, start fw error recovery\n");
Vladimir Kondratiev8ad66002015-07-30 13:51:54 +0300361 wil_fw_error_recovery(wil);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300362}
363
Vladimir Kondratievc33407a2014-10-01 15:05:24 +0300364static int wil_wait_for_recovery(struct wil6210_priv *wil)
365{
366 if (wait_event_interruptible(wil->wq, wil->recovery_state !=
367 fw_recovery_pending)) {
368 wil_err(wil, "Interrupt, canceling recovery\n");
369 return -ERESTARTSYS;
370 }
371 if (wil->recovery_state != fw_recovery_running) {
372 wil_info(wil, "Recovery cancelled\n");
373 return -EINTR;
374 }
375 wil_info(wil, "Proceed with recovery\n");
376 return 0;
377}
378
379void wil_set_recovery_state(struct wil6210_priv *wil, int state)
380{
Lazar Alexei3190cc62017-02-23 14:34:14 +0200381 wil_dbg_misc(wil, "set_recovery_state: %d -> %d\n",
Vladimir Kondratievc33407a2014-10-01 15:05:24 +0300382 wil->recovery_state, state);
383
384 wil->recovery_state = state;
385 wake_up_interruptible(&wil->wq);
386}
387
Lior David375a1732016-03-01 19:18:16 +0200388bool wil_is_recovery_blocked(struct wil6210_priv *wil)
389{
390 return no_fw_recovery && (wil->recovery_state == fw_recovery_pending);
391}
392
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200393static void wil_fw_error_worker(struct work_struct *work)
394{
Vladimir Kondratievc33407a2014-10-01 15:05:24 +0300395 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
396 fw_error_worker);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200397 struct wireless_dev *wdev = wil->wdev;
Hamad Kadmany7c6746d2017-08-21 22:50:58 +0300398 struct net_device *ndev = wil_to_ndev(wil);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200399
400 wil_dbg_misc(wil, "fw error worker\n");
401
Hamad Kadmany7c6746d2017-08-21 22:50:58 +0300402 if (!(ndev->flags & IFF_UP)) {
Vladimir Kondratievcded9362014-10-28 16:50:06 +0200403 wil_info(wil, "No recovery - interface is down\n");
404 return;
405 }
406
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300407 /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
408 * passed since last recovery attempt
409 */
410 if (time_is_after_jiffies(wil->last_fw_recovery +
411 WIL6210_FW_RECOVERY_TO))
412 wil->recovery_count++;
413 else
414 wil->recovery_count = 1; /* fw was alive for a long time */
415
416 if (wil->recovery_count > WIL6210_FW_RECOVERY_RETRIES) {
417 wil_err(wil, "too many recovery attempts (%d), giving up\n",
418 wil->recovery_count);
419 return;
420 }
421
422 wil->last_fw_recovery = jiffies;
423
Lior Davida98e7ac2016-12-06 09:31:12 +0200424 wil_info(wil, "fw error recovery requested (try %d)...\n",
425 wil->recovery_count);
426 if (!no_fw_recovery)
427 wil->recovery_state = fw_recovery_running;
428 if (wil_wait_for_recovery(wil) != 0)
429 return;
430
Vladimir Kondratiev9c3bde52014-03-17 15:34:21 +0200431 mutex_lock(&wil->mutex);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200432 switch (wdev->iftype) {
433 case NL80211_IFTYPE_STATION:
434 case NL80211_IFTYPE_P2P_CLIENT:
435 case NL80211_IFTYPE_MONITOR:
Lior Davida98e7ac2016-12-06 09:31:12 +0200436 /* silent recovery, upper layers will see disconnect */
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +0300437 __wil_down(wil);
438 __wil_up(wil);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200439 break;
440 case NL80211_IFTYPE_AP:
441 case NL80211_IFTYPE_P2P_GO:
Vladimir Kondratieve2405372014-10-28 16:50:09 +0200442 wil_info(wil, "No recovery for AP-like interface\n");
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200443 /* recovery in these modes is done by upper layers */
444 break;
445 default:
Vladimir Kondratieve2405372014-10-28 16:50:09 +0200446 wil_err(wil, "No recovery - unknown interface type %d\n",
447 wdev->iftype);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200448 break;
449 }
Vladimir Kondratiev9c3bde52014-03-17 15:34:21 +0200450 mutex_unlock(&wil->mutex);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200451}
452
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200453static int wil_find_free_vring(struct wil6210_priv *wil)
454{
455 int i;
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +0300456
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200457 for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
458 if (!wil->vring_tx[i].va)
459 return i;
460 }
461 return -EINVAL;
462}
463
Maya Erez0916d9f2016-01-17 12:39:10 +0200464int wil_tx_init(struct wil6210_priv *wil, int cid)
465{
466 int rc = -EINVAL, ringid;
467
468 if (cid < 0) {
469 wil_err(wil, "No connection pending\n");
470 goto out;
471 }
472 ringid = wil_find_free_vring(wil);
473 if (ringid < 0) {
474 wil_err(wil, "No free vring found\n");
475 goto out;
476 }
477
478 wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n",
479 cid, ringid);
480
481 rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
482 if (rc)
483 wil_err(wil, "wil_vring_init_tx for CID %d vring %d failed\n",
484 cid, ringid);
485
486out:
487 return rc;
488}
489
Vladimir Kondratiev41d6b092015-03-15 16:00:23 +0200490int wil_bcast_init(struct wil6210_priv *wil)
491{
492 int ri = wil->bcast_vring, rc;
493
494 if ((ri >= 0) && wil->vring_tx[ri].va)
495 return 0;
496
497 ri = wil_find_free_vring(wil);
498 if (ri < 0)
499 return ri;
500
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300501 wil->bcast_vring = ri;
Vladimir Kondratiev41d6b092015-03-15 16:00:23 +0200502 rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300503 if (rc)
504 wil->bcast_vring = -1;
Vladimir Kondratiev41d6b092015-03-15 16:00:23 +0200505
506 return rc;
507}
508
509void wil_bcast_fini(struct wil6210_priv *wil)
510{
511 int ri = wil->bcast_vring;
512
513 if (ri < 0)
514 return;
515
516 wil->bcast_vring = -1;
517 wil_vring_fini_tx(wil, ri);
518}
519
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800520int wil_priv_init(struct wil6210_priv *wil)
521{
Dedy Lanskyec81b5a2014-09-10 16:34:42 +0300522 uint i;
523
Lazar Alexei3190cc62017-02-23 14:34:14 +0200524 wil_dbg_misc(wil, "priv_init\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800525
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200526 memset(wil->sta, 0, sizeof(wil->sta));
Dedy Lanskyec81b5a2014-09-10 16:34:42 +0300527 for (i = 0; i < WIL6210_MAX_CID; i++)
528 spin_lock_init(&wil->sta[i].tid_rx_lock);
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200529
Maya Erez875e9432016-01-28 19:24:02 +0200530 for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
531 spin_lock_init(&wil->vring_tx_data[i].lock);
532
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800533 mutex_init(&wil->mutex);
534 mutex_init(&wil->wmi_mutex);
Vladimir Kondratiev40822a92015-01-25 10:52:50 +0200535 mutex_init(&wil->probe_client_mutex);
Lior David4332cac2016-03-01 19:18:13 +0200536 mutex_init(&wil->p2p_wdev_mutex);
Maya Erez349214c2016-04-26 14:41:41 +0300537 mutex_init(&wil->halp.lock);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800538
539 init_completion(&wil->wmi_ready);
Dedy Lansky59502642014-09-10 16:34:46 +0300540 init_completion(&wil->wmi_call);
Maya Erez349214c2016-04-26 14:41:41 +0300541 init_completion(&wil->halp.comp);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800542
Vladimir Kondratiev41d6b092015-03-15 16:00:23 +0200543 wil->bcast_vring = -1;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800544 setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300545 setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
Dedy Lanskye6d68342016-03-01 19:18:12 +0200546 setup_timer(&wil->p2p.discovery_timer, wil_p2p_discovery_timer_fn,
547 (ulong)wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800548
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800549 INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
550 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200551 INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
Vladimir Kondratiev40822a92015-01-25 10:52:50 +0200552 INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
Lior David42ba1c222017-02-15 20:37:20 +0200553 INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800554
555 INIT_LIST_HEAD(&wil->pending_wmi_ev);
Vladimir Kondratiev40822a92015-01-25 10:52:50 +0200556 INIT_LIST_HEAD(&wil->probe_client_pending);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800557 spin_lock_init(&wil->wmi_ev_lock);
Dedy Lansky970a98f2016-12-06 08:26:49 +0200558 spin_lock_init(&wil->net_queue_lock);
559 wil->net_queue_stopped = 1;
Vladimir Kondratievc33407a2014-10-01 15:05:24 +0300560 init_waitqueue_head(&wil->wq);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800561
Lior David8f1b5e02017-02-28 14:58:27 +0200562 wil_ftm_init(wil);
563
Vladimir Kondratiev32772132014-12-23 09:47:03 +0200564 wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800565 if (!wil->wmi_wq)
566 return -EAGAIN;
567
Vladimir Kondratiev32772132014-12-23 09:47:03 +0200568 wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
569 if (!wil->wq_service)
570 goto out_wmi_wq;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800571
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300572 wil->last_fw_recovery = jiffies;
Vladimir Shulman1f80af22015-01-25 10:52:48 +0200573 wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT;
574 wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT;
575 wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT;
576 wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT;
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300577
Vladimir Kondratievab954622014-12-23 09:47:20 +0200578 if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
579 rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
Lazar Alexei472bec22017-05-04 22:41:44 +0300580
581 wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT;
582
Maya Ereze3309bf2017-05-15 16:57:46 +0300583 wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST |
584 WMI_WAKEUP_TRIGGER_BCAST;
Maya Erez2f9f6422017-08-21 22:43:32 +0300585 memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
586 wil->suspend_stats.min_suspend_time = ULONG_MAX;
Gidon Studinski1c9a1932017-08-21 22:55:15 +0300587 wil->vring_idle_trsh = 16;
Maya Ereze3309bf2017-05-15 16:57:46 +0300588
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800589 return 0;
Vladimir Kondratiev32772132014-12-23 09:47:03 +0200590
591out_wmi_wq:
592 destroy_workqueue(wil->wmi_wq);
593
594 return -EAGAIN;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800595}
596
Lior David704099f2017-05-04 21:31:02 +0300597void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
598{
Maya Ereze3309bf2017-05-15 16:57:46 +0300599 if (wil->platform_ops.bus_request) {
600 wil->bus_request_kbps = kbps;
Lior David704099f2017-05-04 21:31:02 +0300601 wil->platform_ops.bus_request(wil->platform_handle, kbps);
Maya Ereze3309bf2017-05-15 16:57:46 +0300602 }
Lior David704099f2017-05-04 21:31:02 +0300603}
604
Vladimir Kondratievb516fcc2014-10-28 16:50:08 +0200605/**
606 * wil6210_disconnect - disconnect one connection
607 * @wil: driver context
608 * @bssid: peer to disconnect, NULL to disconnect all
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200609 * @reason_code: Reason code for the Disassociation frame
Vladimir Kondratievb516fcc2014-10-28 16:50:08 +0200610 * @from_event: whether is invoked from FW event handler
611 *
612 * Disconnect and release associated resources. If invoked not from the
613 * FW event handler, issue WMI command(s) to trigger MAC disconnect.
614 */
615void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200616 u16 reason_code, bool from_event)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800617{
Lazar Alexei3190cc62017-02-23 14:34:14 +0200618 wil_dbg_misc(wil, "disconnect\n");
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +0300619
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800620 del_timer_sync(&wil->connect_timer);
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200621 _wil6210_disconnect(wil, bssid, reason_code, from_event);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800622}
623
624void wil_priv_deinit(struct wil6210_priv *wil)
625{
Lazar Alexei3190cc62017-02-23 14:34:14 +0200626 wil_dbg_misc(wil, "priv_deinit\n");
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +0300627
Lior David8f1b5e02017-02-28 14:58:27 +0200628 wil_ftm_deinit(wil);
Vladimir Kondratievc33407a2014-10-01 15:05:24 +0300629 wil_set_recovery_state(wil, fw_recovery_idle);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300630 del_timer_sync(&wil->scan_timer);
Dedy Lanskye6d68342016-03-01 19:18:12 +0200631 del_timer_sync(&wil->p2p.discovery_timer);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800632 cancel_work_sync(&wil->disconnect_worker);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200633 cancel_work_sync(&wil->fw_error_worker);
Dedy Lanskye6d68342016-03-01 19:18:12 +0200634 cancel_work_sync(&wil->p2p.discovery_expired_work);
Lior David42ba1c222017-02-15 20:37:20 +0200635 cancel_work_sync(&wil->p2p.delayed_listen_work);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200636 mutex_lock(&wil->mutex);
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200637 wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200638 mutex_unlock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800639 wmi_event_flush(wil);
Vladimir Kondratiev40822a92015-01-25 10:52:50 +0200640 wil_probe_client_flush(wil);
641 cancel_work_sync(&wil->probe_client_worker);
Vladimir Kondratiev32772132014-12-23 09:47:03 +0200642 destroy_workqueue(wil->wq_service);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800643 destroy_workqueue(wil->wmi_wq);
644}
645
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300646static inline void wil_halt_cpu(struct wil6210_priv *wil)
647{
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300648 wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
649 wil_w(wil, RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300650}
651
652static inline void wil_release_cpu(struct wil6210_priv *wil)
653{
654 /* Start CPU */
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300655 wil_w(wil, RGF_USER_USER_CPU_0, 1);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300656}
657
Lior David42ce0aa2017-03-27 21:42:25 +0300658static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode)
Lior David1f1a3612016-03-01 19:18:18 +0200659{
Lior David42ce0aa2017-03-27 21:42:25 +0300660 wil_info(wil, "oob_mode to %d\n", mode);
661 switch (mode) {
662 case 0:
663 wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE |
664 BIT_USER_OOB_R2_MODE);
665 break;
666 case 1:
667 wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_R2_MODE);
Lior David1f1a3612016-03-01 19:18:18 +0200668 wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
Lior David42ce0aa2017-03-27 21:42:25 +0300669 break;
670 case 2:
Lior David1f1a3612016-03-01 19:18:18 +0200671 wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
Lior David42ce0aa2017-03-27 21:42:25 +0300672 wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_R2_MODE);
673 break;
674 default:
675 wil_err(wil, "invalid oob_mode: %d\n", mode);
676 }
Lior David1f1a3612016-03-01 19:18:18 +0200677}
678
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300679static int wil_target_reset(struct wil6210_priv *wil)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800680{
Vladimir Kondratiev98a65b52014-03-17 15:34:12 +0200681 int delay = 0;
Vladimir Kondratievbb6c8dc2015-04-30 16:25:07 +0300682 u32 x, x1 = 0;
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200683
Vladimir Kondratiev1aeda132014-12-23 09:47:18 +0200684 wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300685
686 /* Clear MAC link up */
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300687 wil_s(wil, RGF_HP_CTRL, BIT(15));
688 wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
689 wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300690
691 wil_halt_cpu(wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800692
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200693 /* clear all boot loader "ready" bits */
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300694 wil_w(wil, RGF_USER_BL +
695 offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0);
Vladimir Kondratievcce477112014-12-01 15:36:31 +0200696 /* Clear Fw Download notification */
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300697 wil_c(wil, RGF_USER_USAGE_6, BIT(0));
Vladimir Kondratievcce477112014-12-01 15:36:31 +0200698
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300699 wil_s(wil, RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
Vladimir Kondratiev9a5511b2015-02-15 14:02:31 +0200700 /* XTAL stabilization should take about 3ms */
701 usleep_range(5000, 7000);
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300702 x = wil_r(wil, RGF_CAF_PLL_LOCK_STATUS);
Vladimir Kondratiev9a5511b2015-02-15 14:02:31 +0200703 if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) {
704 wil_err(wil, "Xtal stabilization timeout\n"
705 "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x);
706 return -ETIME;
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300707 }
Vladimir Kondratiev9a5511b2015-02-15 14:02:31 +0200708 /* switch 10k to XTAL*/
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300709 wil_c(wil, RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF);
Vladimir Kondratiev9a5511b2015-02-15 14:02:31 +0200710 /* 40 MHz */
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300711 wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL);
Vladimir Kondratiev9a5511b2015-02-15 14:02:31 +0200712
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300713 wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
714 wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300715
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300716 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
717 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
718 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0);
719 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800720
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300721 wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
722 wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300723
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300724 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
725 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
726 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
727 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800728
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300729 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
730 /* reset A2 PCIE AHB */
731 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300732
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300733 wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800734
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200735 /* wait until device ready. typical time is 20..80 msec */
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200736 do {
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300737 msleep(RST_DELAY);
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300738 x = wil_r(wil, RGF_USER_BL +
739 offsetof(struct bl_dedicated_registers_v0,
740 boot_loader_ready));
Vladimir Kondratievbb6c8dc2015-04-30 16:25:07 +0300741 if (x1 != x) {
742 wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
743 x1 = x;
744 }
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300745 if (delay++ > RST_COUNT) {
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200746 wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
Vladimir Kondratiev48516292014-10-28 16:50:07 +0200747 x);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300748 return -ETIME;
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200749 }
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +0300750 } while (x != BL_READY);
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200751
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300752 wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
Vladimir Kondratiev972072a2014-03-17 15:34:15 +0200753
Vladimir Kondratieve3351272015-02-15 14:02:32 +0200754 /* enable fix for HW bug related to the SA/DA swap in AP Rx */
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +0300755 wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN |
756 BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC);
Vladimir Kondratieve3351272015-02-15 14:02:32 +0200757
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300758 wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300759 return 0;
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300760}
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800761
Lior Davidde21eba2017-02-15 20:33:10 +0200762static void wil_collect_fw_info(struct wil6210_priv *wil)
763{
764 struct wiphy *wiphy = wil_to_wiphy(wil);
765 u8 retry_short;
766 int rc;
767
768 rc = wmi_get_mgmt_retry(wil, &retry_short);
769 if (!rc) {
770 wiphy->retry_short = retry_short;
771 wil_dbg_misc(wil, "FW retry_short: %d\n", retry_short);
772 }
773}
774
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800775void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
776{
777 le32_to_cpus(&r->base);
778 le16_to_cpus(&r->entry_size);
779 le16_to_cpus(&r->size);
780 le32_to_cpus(&r->tail);
781 le32_to_cpus(&r->head);
782}
783
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200784static int wil_get_bl_info(struct wil6210_priv *wil)
785{
786 struct net_device *ndev = wil_to_ndev(wil);
Hamad Kadmanyb42f1192016-03-01 19:18:06 +0200787 struct wiphy *wiphy = wil_to_wiphy(wil);
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +0300788 union {
789 struct bl_dedicated_registers_v0 bl0;
790 struct bl_dedicated_registers_v1 bl1;
791 } bl;
792 u32 bl_ver;
793 u8 *mac;
794 u16 rf_status;
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200795
Vladimir Kondratiev19c871c2015-07-30 13:52:07 +0300796 wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL),
797 sizeof(bl));
798 bl_ver = le32_to_cpu(bl.bl0.boot_loader_struct_version);
799 mac = bl.bl0.mac_address;
800
801 if (bl_ver == 0) {
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +0300802 le32_to_cpus(&bl.bl0.rf_type);
803 le32_to_cpus(&bl.bl0.baseband_type);
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +0300804 rf_status = 0; /* actually, unknown */
805 wil_info(wil,
806 "Boot Loader struct v%d: MAC = %pM RF = 0x%08x bband = 0x%08x\n",
807 bl_ver, mac,
808 bl.bl0.rf_type, bl.bl0.baseband_type);
809 wil_info(wil, "Boot Loader build unknown for struct v0\n");
Vladimir Kondratiev19c871c2015-07-30 13:52:07 +0300810 } else {
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +0300811 le16_to_cpus(&bl.bl1.rf_type);
812 rf_status = le16_to_cpu(bl.bl1.rf_status);
813 le32_to_cpus(&bl.bl1.baseband_type);
814 le16_to_cpus(&bl.bl1.bl_version_subminor);
815 le16_to_cpus(&bl.bl1.bl_version_build);
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +0300816 wil_info(wil,
817 "Boot Loader struct v%d: MAC = %pM RF = 0x%04x (status 0x%04x) bband = 0x%08x\n",
818 bl_ver, mac,
819 bl.bl1.rf_type, rf_status,
820 bl.bl1.baseband_type);
821 wil_info(wil, "Boot Loader build %d.%d.%d.%d\n",
822 bl.bl1.bl_version_major, bl.bl1.bl_version_minor,
823 bl.bl1.bl_version_subminor, bl.bl1.bl_version_build);
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200824 }
825
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +0300826 if (!is_valid_ether_addr(mac)) {
827 wil_err(wil, "BL: Invalid MAC %pM\n", mac);
828 return -EINVAL;
829 }
830
831 ether_addr_copy(ndev->perm_addr, mac);
Hamad Kadmanyb42f1192016-03-01 19:18:06 +0200832 ether_addr_copy(wiphy->perm_addr, mac);
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200833 if (!is_valid_ether_addr(ndev->dev_addr))
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +0300834 ether_addr_copy(ndev->dev_addr, mac);
835
836 if (rf_status) {/* bad RF cable? */
837 wil_err(wil, "RF communication error 0x%04x",
838 rf_status);
839 return -EAGAIN;
840 }
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200841
842 return 0;
843}
844
Vladimir Kondratiev409ead52015-07-30 13:52:06 +0300845static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err)
846{
847 u32 bl_assert_code, bl_assert_blink, bl_magic_number;
848 u32 bl_ver = wil_r(wil, RGF_USER_BL +
849 offsetof(struct bl_dedicated_registers_v0,
850 boot_loader_struct_version));
851
852 if (bl_ver < 2)
853 return;
854
855 bl_assert_code = wil_r(wil, RGF_USER_BL +
856 offsetof(struct bl_dedicated_registers_v1,
857 bl_assert_code));
858 bl_assert_blink = wil_r(wil, RGF_USER_BL +
859 offsetof(struct bl_dedicated_registers_v1,
860 bl_assert_blink));
861 bl_magic_number = wil_r(wil, RGF_USER_BL +
862 offsetof(struct bl_dedicated_registers_v1,
863 bl_magic_number));
864
865 if (is_err) {
866 wil_err(wil,
867 "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n",
868 bl_assert_code, bl_assert_blink, bl_magic_number);
869 } else {
870 wil_dbg_misc(wil,
871 "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n",
872 bl_assert_code, bl_assert_blink, bl_magic_number);
873 }
874}
875
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800876static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
877{
878 ulong to = msecs_to_jiffies(1000);
879 ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +0300880
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800881 if (0 == left) {
882 wil_err(wil, "Firmware not ready\n");
883 return -ETIME;
884 } else {
Vladimir Kondratiev15e23122014-04-08 11:36:16 +0300885 wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
886 jiffies_to_msecs(to-left), wil->hw_version);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800887 }
888 return 0;
889}
890
Maya Erez4cbb5852017-02-16 15:26:09 +0200891void wil_abort_scan(struct wil6210_priv *wil, bool sync)
892{
893 int rc;
894 struct cfg80211_scan_info info = {
895 .aborted = true,
896 };
897
898 lockdep_assert_held(&wil->p2p_wdev_mutex);
899
900 if (!wil->scan_request)
901 return;
902
903 wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request);
904 del_timer_sync(&wil->scan_timer);
905 mutex_unlock(&wil->p2p_wdev_mutex);
906 rc = wmi_abort_scan(wil);
907 if (!rc && sync)
908 wait_event_interruptible_timeout(wil->wq, !wil->scan_request,
909 msecs_to_jiffies(
910 WAIT_FOR_SCAN_ABORT_MS));
911
912 mutex_lock(&wil->p2p_wdev_mutex);
913 if (wil->scan_request) {
914 cfg80211_scan_done(wil->scan_request, &info);
915 wil->scan_request = NULL;
916 }
917}
918
Lazar Alexei472bec22017-05-04 22:41:44 +0300919int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile)
920{
921 int rc;
922
923 if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) {
924 wil_err(wil, "set_power_mgmt not supported\n");
925 return -EOPNOTSUPP;
926 }
927
928 rc = wmi_ps_dev_profile_cfg(wil, ps_profile);
929 if (rc)
930 wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc);
931 else
932 wil->ps_profile = ps_profile;
933
934 return rc;
935}
936
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800937/*
938 * We reset all the structures, and we reset the UMAC.
939 * After calling this routine, you're expected to reload
940 * the firmware.
941 */
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +0200942int wil_reset(struct wil6210_priv *wil, bool load_fw)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800943{
944 int rc;
945
Lazar Alexei3190cc62017-02-23 14:34:14 +0200946 wil_dbg_misc(wil, "reset\n");
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +0300947
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200948 WARN_ON(!mutex_is_locked(&wil->mutex));
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200949 WARN_ON(test_bit(wil_status_napi_en, wil->status));
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200950
Vladimir Kondratievbfc2dc72015-03-30 11:28:50 +0300951 if (debug_fw) {
952 static const u8 mac[ETH_ALEN] = {
953 0x00, 0xde, 0xad, 0x12, 0x34, 0x56,
954 };
955 struct net_device *ndev = wil_to_ndev(wil);
956
957 ether_addr_copy(ndev->perm_addr, mac);
958 ether_addr_copy(ndev->dev_addr, ndev->perm_addr);
959 return 0;
960 }
961
Vladimir Kondratiev67131a12015-07-30 13:51:55 +0300962 if (wil->hw_version == HW_VER_UNKNOWN)
963 return -ENODEV;
964
Maya Erez53d6aa62017-03-15 20:16:37 +0200965 wil_dbg_misc(wil, "Prevent DS in BL & mark FW to set T_POWER_ON=0\n");
966 wil_s(wil, RGF_USER_USAGE_8, BIT_USER_PREVENT_DEEP_SLEEP |
967 BIT_USER_SUPPORT_T_POWER_ON_0);
968
Maya Erez5f0823e2016-03-01 19:18:11 +0200969 if (wil->platform_ops.notify) {
970 rc = wil->platform_ops.notify(wil->platform_handle,
971 WIL_PLATFORM_EVT_PRE_RESET);
972 if (rc)
Lazar Alexei3190cc62017-02-23 14:34:14 +0200973 wil_err(wil, "PRE_RESET platform notify failed, rc %d\n",
974 rc);
Maya Erez5f0823e2016-03-01 19:18:11 +0200975 }
976
Hamad Kadmanyf13e0632015-10-04 10:23:27 +0300977 set_bit(wil_status_resetting, wil->status);
978
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200979 cancel_work_sync(&wil->disconnect_worker);
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +0200980 wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
Vladimir Kondratiev41d6b092015-03-15 16:00:23 +0200981 wil_bcast_fini(wil);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200982
Maya Erez10d599a2016-05-09 21:57:11 +0300983 /* Disable device led before reset*/
984 wmi_led_cfg(wil, false);
985
Hamad Kadmany8fc4c482017-05-04 22:37:57 +0300986 mutex_lock(&wil->p2p_wdev_mutex);
987 wil_abort_scan(wil, false);
988 mutex_unlock(&wil->p2p_wdev_mutex);
989
Maya Erez452133a2015-11-24 09:30:15 +0200990 /* prevent NAPI from being scheduled and prevent wmi commands */
991 mutex_lock(&wil->wmi_mutex);
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200992 bitmap_zero(wil->status, wil_status_last);
Maya Erez452133a2015-11-24 09:30:15 +0200993 mutex_unlock(&wil->wmi_mutex);
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200994
Vladimir Kondratieve4dbb092014-09-10 16:34:49 +0300995 wil_mask_irq(wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800996
Vladimir Kondratieve08b5902013-01-28 18:31:05 +0200997 wmi_event_flush(wil);
998
Vladimir Kondratiev32772132014-12-23 09:47:03 +0200999 flush_workqueue(wil->wq_service);
Vladimir Kondratieve08b5902013-01-28 18:31:05 +02001000 flush_workqueue(wil->wmi_wq);
1001
Vladimir Kondratiev409ead52015-07-30 13:52:06 +03001002 wil_bl_crash_info(wil, false);
Hamad Kadmany2953f792017-02-22 15:18:58 +02001003 wil_disable_irq(wil);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +03001004 rc = wil_target_reset(wil);
Hamad Kadmany2953f792017-02-22 15:18:58 +02001005 wil6210_clear_irq(wil);
1006 wil_enable_irq(wil);
Vladimir Kondratiev8bf6adb2014-03-17 15:34:17 +02001007 wil_rx_fini(wil);
Vladimir Kondratiev409ead52015-07-30 13:52:06 +03001008 if (rc) {
1009 wil_bl_crash_info(wil, true);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +03001010 return rc;
Vladimir Kondratiev409ead52015-07-30 13:52:06 +03001011 }
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +03001012
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001013 rc = wil_get_bl_info(wil);
Vladimir Kondratievf1ad8c92015-07-30 13:51:49 +03001014 if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
1015 rc = 0;
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001016 if (rc)
1017 return rc;
1018
Lior David1f1a3612016-03-01 19:18:18 +02001019 wil_set_oob_mode(wil, oob_mode);
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001020 if (load_fw) {
Lazar Alexeid3c6fa92017-02-09 13:57:36 +02001021 wil_info(wil, "Use firmware <%s> + board <%s>\n",
1022 wil->wil_fw_name, WIL_BOARD_FILE_NAME);
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001023
Vladimir Kondratiev151a9702014-09-10 16:34:30 +03001024 wil_halt_cpu(wil);
Lior David13cd9f72016-08-22 12:42:22 +03001025 memset(wil->fw_version, 0, sizeof(wil->fw_version));
Vladimir Kondratiev151a9702014-09-10 16:34:30 +03001026 /* Loading f/w from the file */
Lazar Alexeid3c6fa92017-02-09 13:57:36 +02001027 rc = wil_request_firmware(wil, wil->wil_fw_name, true);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +03001028 if (rc)
1029 return rc;
Lazar Alexeid3c6fa92017-02-09 13:57:36 +02001030 rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true);
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001031 if (rc)
1032 return rc;
Vladimir Kondratiev151a9702014-09-10 16:34:30 +03001033
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001034 /* Mark FW as loaded from host */
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +03001035 wil_s(wil, RGF_USER_USAGE_6, 1);
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001036
1037 /* clear any interrupts which on-card-firmware
1038 * may have set
1039 */
Vladimir Kondratiev151a9702014-09-10 16:34:30 +03001040 wil6210_clear_irq(wil);
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001041 /* CAF_ICR - clear and mask */
1042 /* it is W1C, clear by writing back same value */
Vladimir Kondratievb9eeb512015-07-30 13:52:03 +03001043 wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
1044 wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +03001045
Dedy Lanskyecac1072017-08-21 22:53:18 +03001046 if (wil->fw_calib_result > 0) {
1047 __le32 val = cpu_to_le32(wil->fw_calib_result |
1048 (CALIB_RESULT_SIGNATURE << 8));
1049 wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val);
1050 }
1051
Vladimir Kondratiev151a9702014-09-10 16:34:30 +03001052 wil_release_cpu(wil);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +03001053 }
Vladimir Kondratiev8bf6adb2014-03-17 15:34:17 +02001054
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001055 /* init after reset */
Vladimir Kondratiev02beaf12015-03-08 15:42:03 +02001056 wil->ap_isolate = 0;
Wolfram Sang16735d02013-11-14 14:32:02 -08001057 reinit_completion(&wil->wmi_ready);
Dedy Lansky59502642014-09-10 16:34:46 +03001058 reinit_completion(&wil->wmi_call);
Maya Erez349214c2016-04-26 14:41:41 +03001059 reinit_completion(&wil->halp.comp);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001060
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001061 if (load_fw) {
1062 wil_configure_interrupt_moderation(wil);
1063 wil_unmask_irq(wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001064
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001065 /* we just started MAC, wait for FW ready */
1066 rc = wil_wait_for_fw_ready(wil);
Maya Erez5f0823e2016-03-01 19:18:11 +02001067 if (rc)
1068 return rc;
1069
1070 /* check FW is responsive */
1071 rc = wmi_echo(wil);
1072 if (rc) {
Lazar Alexei3190cc62017-02-23 14:34:14 +02001073 wil_err(wil, "wmi_echo failed, rc %d\n", rc);
Maya Erez5f0823e2016-03-01 19:18:11 +02001074 return rc;
1075 }
1076
Lazar Alexei472bec22017-05-04 22:41:44 +03001077 if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
1078 wil_ps_update(wil, wil->ps_profile);
1079
Dedy Lansky1b752712017-03-20 15:35:51 +02001080 if (wil->tt_data_set)
1081 wmi_set_tt_cfg(wil, &wil->tt_data);
1082
Lior Davidde21eba2017-02-15 20:33:10 +02001083 wil_collect_fw_info(wil);
1084
Maya Erez5f0823e2016-03-01 19:18:11 +02001085 if (wil->platform_ops.notify) {
1086 rc = wil->platform_ops.notify(wil->platform_handle,
1087 WIL_PLATFORM_EVT_FW_RDY);
1088 if (rc) {
Lazar Alexei3190cc62017-02-23 14:34:14 +02001089 wil_err(wil, "FW_RDY notify failed, rc %d\n",
1090 rc);
Maya Erez5f0823e2016-03-01 19:18:11 +02001091 rc = 0;
1092 }
1093 }
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001094 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001095
1096 return rc;
1097}
1098
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +02001099void wil_fw_error_recovery(struct wil6210_priv *wil)
1100{
1101 wil_dbg_misc(wil, "starting fw error recovery\n");
Hamad Kadmanyf13e0632015-10-04 10:23:27 +03001102
1103 if (test_bit(wil_status_resetting, wil->status)) {
1104 wil_info(wil, "Reset already in progress\n");
1105 return;
1106 }
1107
Vladimir Kondratievc33407a2014-10-01 15:05:24 +03001108 wil->recovery_state = fw_recovery_pending;
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +02001109 schedule_work(&wil->fw_error_worker);
1110}
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001111
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +03001112int __wil_up(struct wil6210_priv *wil)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001113{
1114 struct net_device *ndev = wil_to_ndev(wil);
1115 struct wireless_dev *wdev = wil->wdev;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001116 int rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001117
Vladimir Kondratiev097638a2014-03-17 15:34:25 +02001118 WARN_ON(!mutex_is_locked(&wil->mutex));
1119
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001120 rc = wil_reset(wil, true);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001121 if (rc)
1122 return rc;
1123
Vladimir Kondratieve31b2562013-06-09 09:12:55 +03001124 /* Rx VRING. After MAC and beacon */
Vladimir Kondratievd3762b42014-12-01 15:35:02 +02001125 rc = wil_rx_init(wil, 1 << rx_ring_order);
Vladimir Kondratieve31b2562013-06-09 09:12:55 +03001126 if (rc)
1127 return rc;
1128
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001129 switch (wdev->iftype) {
1130 case NL80211_IFTYPE_STATION:
Vladimir Kondratiev77438822013-01-28 18:31:06 +02001131 wil_dbg_misc(wil, "type: STATION\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001132 ndev->type = ARPHRD_ETHER;
1133 break;
1134 case NL80211_IFTYPE_AP:
Vladimir Kondratiev77438822013-01-28 18:31:06 +02001135 wil_dbg_misc(wil, "type: AP\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001136 ndev->type = ARPHRD_ETHER;
1137 break;
1138 case NL80211_IFTYPE_P2P_CLIENT:
Vladimir Kondratiev77438822013-01-28 18:31:06 +02001139 wil_dbg_misc(wil, "type: P2P_CLIENT\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001140 ndev->type = ARPHRD_ETHER;
1141 break;
1142 case NL80211_IFTYPE_P2P_GO:
Vladimir Kondratiev77438822013-01-28 18:31:06 +02001143 wil_dbg_misc(wil, "type: P2P_GO\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001144 ndev->type = ARPHRD_ETHER;
1145 break;
1146 case NL80211_IFTYPE_MONITOR:
Vladimir Kondratiev77438822013-01-28 18:31:06 +02001147 wil_dbg_misc(wil, "type: Monitor\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001148 ndev->type = ARPHRD_IEEE80211_RADIOTAP;
1149 /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
1150 break;
1151 default:
1152 return -EOPNOTSUPP;
1153 }
1154
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001155 /* MAC address - pre-requisite for other commands */
1156 wmi_set_mac_address(wil, ndev->dev_addr);
1157
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +03001158 wil_dbg_misc(wil, "NAPI enable\n");
Vladimir Kondratieve0287c42013-05-12 14:43:36 +03001159 napi_enable(&wil->napi_rx);
1160 napi_enable(&wil->napi_tx);
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +02001161 set_bit(wil_status_napi_en, wil->status);
Vladimir Kondratieve0287c42013-05-12 14:43:36 +03001162
Lior David704099f2017-05-04 21:31:02 +03001163 wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
Vladimir Kondratievf772ebf2014-09-10 16:34:35 +03001164
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001165 return 0;
1166}
1167
1168int wil_up(struct wil6210_priv *wil)
1169{
1170 int rc;
1171
Lazar Alexei3190cc62017-02-23 14:34:14 +02001172 wil_dbg_misc(wil, "up\n");
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +03001173
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001174 mutex_lock(&wil->mutex);
1175 rc = __wil_up(wil);
1176 mutex_unlock(&wil->mutex);
1177
1178 return rc;
1179}
1180
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +03001181int __wil_down(struct wil6210_priv *wil)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001182{
Vladimir Kondratiev097638a2014-03-17 15:34:25 +02001183 WARN_ON(!mutex_is_locked(&wil->mutex));
1184
Lazar Alexeib0c0e682016-08-18 16:52:14 +03001185 set_bit(wil_status_resetting, wil->status);
1186
Lior David704099f2017-05-04 21:31:02 +03001187 wil6210_bus_request(wil, 0);
Vladimir Kondratievf772ebf2014-09-10 16:34:35 +03001188
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +03001189 wil_disable_irq(wil);
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +02001190 if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +03001191 napi_disable(&wil->napi_rx);
1192 napi_disable(&wil->napi_tx);
1193 wil_dbg_misc(wil, "NAPI disable\n");
1194 }
1195 wil_enable_irq(wil);
Vladimir Kondratieve0287c42013-05-12 14:43:36 +03001196
Lior David8f1b5e02017-02-28 14:58:27 +02001197 wil_ftm_stop_operations(wil);
Dedy Lanskye6d68342016-03-01 19:18:12 +02001198
Lior David5ffae432016-08-22 12:42:19 +03001199 mutex_lock(&wil->p2p_wdev_mutex);
Maya Erez4cbb5852017-02-16 15:26:09 +02001200 wil_p2p_stop_radio_operations(wil);
1201 wil_abort_scan(wil, false);
Lior David5ffae432016-08-22 12:42:19 +03001202 mutex_unlock(&wil->p2p_wdev_mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001203
Vladimir Kondratiev2cd0f022015-02-15 14:02:30 +02001204 wil_reset(wil, false);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001205
1206 return 0;
1207}
1208
1209int wil_down(struct wil6210_priv *wil)
1210{
1211 int rc;
1212
Lazar Alexei3190cc62017-02-23 14:34:14 +02001213 wil_dbg_misc(wil, "down\n");
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +03001214
Vladimir Kondratievc33407a2014-10-01 15:05:24 +03001215 wil_set_recovery_state(wil, fw_recovery_idle);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001216 mutex_lock(&wil->mutex);
1217 rc = __wil_down(wil);
1218 mutex_unlock(&wil->mutex);
1219
1220 return rc;
1221}
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +02001222
1223int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
1224{
1225 int i;
1226 int rc = -ENOENT;
1227
1228 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
1229 if ((wil->sta[i].status != wil_sta_unused) &&
Vladimir Kondratiev108d1eb2014-02-27 16:20:53 +02001230 ether_addr_equal(wil->sta[i].addr, mac)) {
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +02001231 rc = i;
1232 break;
1233 }
1234 }
1235
1236 return rc;
1237}
Maya Erez349214c2016-04-26 14:41:41 +03001238
1239void wil_halp_vote(struct wil6210_priv *wil)
1240{
1241 unsigned long rc;
1242 unsigned long to_jiffies = msecs_to_jiffies(WAIT_FOR_HALP_VOTE_MS);
1243
1244 mutex_lock(&wil->halp.lock);
1245
Lazar Alexei3190cc62017-02-23 14:34:14 +02001246 wil_dbg_irq(wil, "halp_vote: start, HALP ref_cnt (%d)\n",
Lior Davidef86f242016-08-18 16:52:13 +03001247 wil->halp.ref_cnt);
Maya Erez349214c2016-04-26 14:41:41 +03001248
1249 if (++wil->halp.ref_cnt == 1) {
Maya Erez6e64b0c2017-03-27 21:16:39 +03001250 reinit_completion(&wil->halp.comp);
Maya Erez349214c2016-04-26 14:41:41 +03001251 wil6210_set_halp(wil);
1252 rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
Maya Erezf1b77642016-08-18 16:52:12 +03001253 if (!rc) {
Lazar Alexei3190cc62017-02-23 14:34:14 +02001254 wil_err(wil, "HALP vote timed out\n");
Maya Erezf1b77642016-08-18 16:52:12 +03001255 /* Mask HALP as done in case the interrupt is raised */
1256 wil6210_mask_halp(wil);
1257 } else {
Lior Davidef86f242016-08-18 16:52:13 +03001258 wil_dbg_irq(wil,
Lazar Alexei3190cc62017-02-23 14:34:14 +02001259 "halp_vote: HALP vote completed after %d ms\n",
Lior Davidef86f242016-08-18 16:52:13 +03001260 jiffies_to_msecs(to_jiffies - rc));
Maya Erezf1b77642016-08-18 16:52:12 +03001261 }
Maya Erez349214c2016-04-26 14:41:41 +03001262 }
1263
Lazar Alexei3190cc62017-02-23 14:34:14 +02001264 wil_dbg_irq(wil, "halp_vote: end, HALP ref_cnt (%d)\n",
Lior Davidef86f242016-08-18 16:52:13 +03001265 wil->halp.ref_cnt);
Maya Erez349214c2016-04-26 14:41:41 +03001266
1267 mutex_unlock(&wil->halp.lock);
1268}
1269
1270void wil_halp_unvote(struct wil6210_priv *wil)
1271{
1272 WARN_ON(wil->halp.ref_cnt == 0);
1273
1274 mutex_lock(&wil->halp.lock);
1275
Lazar Alexei3190cc62017-02-23 14:34:14 +02001276 wil_dbg_irq(wil, "halp_unvote: start, HALP ref_cnt (%d)\n",
Lior Davidef86f242016-08-18 16:52:13 +03001277 wil->halp.ref_cnt);
Maya Erez349214c2016-04-26 14:41:41 +03001278
1279 if (--wil->halp.ref_cnt == 0) {
1280 wil6210_clear_halp(wil);
Lazar Alexei3190cc62017-02-23 14:34:14 +02001281 wil_dbg_irq(wil, "HALP unvote\n");
Maya Erez349214c2016-04-26 14:41:41 +03001282 }
1283
Lazar Alexei3190cc62017-02-23 14:34:14 +02001284 wil_dbg_irq(wil, "halp_unvote:end, HALP ref_cnt (%d)\n",
Lior Davidef86f242016-08-18 16:52:13 +03001285 wil->halp.ref_cnt);
Maya Erez349214c2016-04-26 14:41:41 +03001286
1287 mutex_unlock(&wil->halp.lock);
1288}