blob: 4a884b415dc00fc99ed5dfcefa1a2e56bdc2e1c0 [file] [log] [blame]
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001/*
Vladimir Kondratiev02525a72014-08-06 10:31:51 +03002 * Copyright (c) 2012-2014 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"
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080023
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +020024static bool no_fw_recovery;
25module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
26MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
27
Vladimir Kondratiev151a9702014-09-10 16:34:30 +030028static bool no_fw_load = true;
29module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
30MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
31
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +030032#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
33#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
34
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080035/*
36 * Due to a hardware issue,
37 * one has to read/write to/from NIC in 32-bit chunks;
38 * regular memcpy_fromio and siblings will
39 * not work on 64-bit platform - it uses 64-bit transactions
40 *
41 * Force 32-bit transactions to enable NIC on 64-bit platforms
42 *
43 * To avoid byte swap on big endian host, __raw_{read|write}l
44 * should be used - {read|write}l would swap bytes to provide
45 * little endian on PCI value in host endianness.
46 */
47void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
48 size_t count)
49{
50 u32 *d = dst;
51 const volatile u32 __iomem *s = src;
52
53 /* size_t is unsigned, if (count%4 != 0) it will wrap */
54 for (count += 4; count > 4; count -= 4)
55 *d++ = __raw_readl(s++);
56}
57
58void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
59 size_t count)
60{
61 volatile u32 __iomem *d = dst;
62 const u32 *s = src;
63
64 for (count += 4; count > 4; count -= 4)
65 __raw_writel(*s++, d++);
66}
67
Vladimir Kondratiev91886b02014-02-27 16:20:50 +020068static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
69{
70 uint i;
Vladimir Kondratievfc58f682014-06-16 19:37:16 +030071 struct net_device *ndev = wil_to_ndev(wil);
72 struct wireless_dev *wdev = wil->wdev;
Vladimir Kondratiev91886b02014-02-27 16:20:50 +020073 struct wil_sta_info *sta = &wil->sta[cid];
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +030074
Vladimir Kondratievfc58f682014-06-16 19:37:16 +030075 wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
76 sta->status);
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +020077
Vladimir Kondratieve58c9f72014-03-17 15:34:06 +020078 sta->data_port_open = false;
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +020079 if (sta->status != wil_sta_unused) {
80 wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
Vladimir Kondratievfc58f682014-06-16 19:37:16 +030081 switch (wdev->iftype) {
82 case NL80211_IFTYPE_AP:
83 case NL80211_IFTYPE_P2P_GO:
84 /* AP-like interface */
85 cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL);
86 break;
87 default:
88 break;
89 }
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +020090 sta->status = wil_sta_unused;
91 }
92
Vladimir Kondratiev91886b02014-02-27 16:20:50 +020093 for (i = 0; i < WIL_STA_TID_NUM; i++) {
94 struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
95 sta->tid_rx[i] = NULL;
96 wil_tid_ampdu_rx_free(wil, r);
97 }
98 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
99 if (wil->vring2cid_tid[i][0] == cid)
100 wil_vring_fini_tx(wil, i);
101 }
102 memset(&sta->stats, 0, sizeof(sta->stats));
103}
104
Johannes Berg3b3a0162014-05-19 17:19:31 +0200105static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800106{
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200107 int cid = -ENOENT;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800108 struct net_device *ndev = wil_to_ndev(wil);
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200109 struct wireless_dev *wdev = wil->wdev;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800110
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200111 might_sleep();
112 if (bssid) {
113 cid = wil_find_cid(wil, bssid);
114 wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
115 } else {
116 wil_dbg_misc(wil, "%s(all)\n", __func__);
117 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800118
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200119 if (cid >= 0) /* disconnect 1 peer */
120 wil_disconnect_cid(wil, cid);
121 else /* disconnect all */
122 for (cid = 0; cid < WIL6210_MAX_CID; cid++)
123 wil_disconnect_cid(wil, cid);
124
125 /* link state */
126 switch (wdev->iftype) {
127 case NL80211_IFTYPE_STATION:
128 case NL80211_IFTYPE_P2P_CLIENT:
129 wil_link_off(wil);
130 if (test_bit(wil_status_fwconnected, &wil->status)) {
131 clear_bit(wil_status_fwconnected, &wil->status);
132 cfg80211_disconnected(ndev,
133 WLAN_STATUS_UNSPECIFIED_FAILURE,
134 NULL, 0, GFP_KERNEL);
135 } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
136 cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
137 WLAN_STATUS_UNSPECIFIED_FAILURE,
138 GFP_KERNEL);
Vladimir Kondratievb4490f42014-02-27 16:20:44 +0200139 }
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200140 clear_bit(wil_status_fwconnecting, &wil->status);
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200141 break;
142 default:
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200143 break;
Vladimir Kondratievb4490f42014-02-27 16:20:44 +0200144 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800145}
146
147static void wil_disconnect_worker(struct work_struct *work)
148{
149 struct wil6210_priv *wil = container_of(work,
150 struct wil6210_priv, disconnect_worker);
151
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200152 mutex_lock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800153 _wil6210_disconnect(wil, NULL);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200154 mutex_unlock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800155}
156
157static void wil_connect_timer_fn(ulong x)
158{
159 struct wil6210_priv *wil = (void *)x;
160
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200161 wil_dbg_misc(wil, "Connect timeout\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800162
163 /* reschedule to thread context - disconnect won't
164 * run from atomic context
165 */
166 schedule_work(&wil->disconnect_worker);
167}
168
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300169static void wil_scan_timer_fn(ulong x)
170{
171 struct wil6210_priv *wil = (void *)x;
172
173 clear_bit(wil_status_fwready, &wil->status);
174 wil_err(wil, "Scan timeout detected, start fw error recovery\n");
175 schedule_work(&wil->fw_error_worker);
176}
177
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200178static void wil_fw_error_worker(struct work_struct *work)
179{
180 struct wil6210_priv *wil = container_of(work,
181 struct wil6210_priv, fw_error_worker);
182 struct wireless_dev *wdev = wil->wdev;
183
184 wil_dbg_misc(wil, "fw error worker\n");
185
186 if (no_fw_recovery)
187 return;
188
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300189 /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
190 * passed since last recovery attempt
191 */
192 if (time_is_after_jiffies(wil->last_fw_recovery +
193 WIL6210_FW_RECOVERY_TO))
194 wil->recovery_count++;
195 else
196 wil->recovery_count = 1; /* fw was alive for a long time */
197
198 if (wil->recovery_count > WIL6210_FW_RECOVERY_RETRIES) {
199 wil_err(wil, "too many recovery attempts (%d), giving up\n",
200 wil->recovery_count);
201 return;
202 }
203
204 wil->last_fw_recovery = jiffies;
205
Vladimir Kondratiev9c3bde52014-03-17 15:34:21 +0200206 mutex_lock(&wil->mutex);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200207 switch (wdev->iftype) {
208 case NL80211_IFTYPE_STATION:
209 case NL80211_IFTYPE_P2P_CLIENT:
210 case NL80211_IFTYPE_MONITOR:
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300211 wil_info(wil, "fw error recovery started (try %d)...\n",
212 wil->recovery_count);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200213 wil_reset(wil);
214
215 /* need to re-allocate Rx ring after reset */
216 wil_rx_init(wil);
217 break;
218 case NL80211_IFTYPE_AP:
219 case NL80211_IFTYPE_P2P_GO:
220 /* recovery in these modes is done by upper layers */
221 break;
222 default:
223 break;
224 }
Vladimir Kondratiev9c3bde52014-03-17 15:34:21 +0200225 mutex_unlock(&wil->mutex);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200226}
227
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200228static int wil_find_free_vring(struct wil6210_priv *wil)
229{
230 int i;
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +0300231
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200232 for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
233 if (!wil->vring_tx[i].va)
234 return i;
235 }
236 return -EINVAL;
237}
238
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200239static void wil_connect_worker(struct work_struct *work)
240{
241 int rc;
242 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
243 connect_worker);
244 int cid = wil->pending_connect_cid;
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200245 int ringid = wil_find_free_vring(wil);
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200246
247 if (cid < 0) {
248 wil_err(wil, "No connection pending\n");
249 return;
250 }
251
252 wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
253
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200254 rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200255 wil->pending_connect_cid = -1;
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200256 if (rc == 0) {
257 wil->sta[cid].status = wil_sta_connected;
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200258 wil_link_on(wil);
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200259 } else {
260 wil->sta[cid].status = wil_sta_unused;
261 }
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200262}
263
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800264int wil_priv_init(struct wil6210_priv *wil)
265{
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200266 wil_dbg_misc(wil, "%s()\n", __func__);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800267
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200268 memset(wil->sta, 0, sizeof(wil->sta));
269
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800270 mutex_init(&wil->mutex);
271 mutex_init(&wil->wmi_mutex);
272
273 init_completion(&wil->wmi_ready);
274
275 wil->pending_connect_cid = -1;
276 setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300277 setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800278
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200279 INIT_WORK(&wil->connect_worker, wil_connect_worker);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800280 INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
281 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200282 INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800283
284 INIT_LIST_HEAD(&wil->pending_wmi_ev);
285 spin_lock_init(&wil->wmi_ev_lock);
286
287 wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
288 if (!wil->wmi_wq)
289 return -EAGAIN;
290
291 wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
292 if (!wil->wmi_wq_conn) {
293 destroy_workqueue(wil->wmi_wq);
294 return -EAGAIN;
295 }
296
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300297 wil->last_fw_recovery = jiffies;
298
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800299 return 0;
300}
301
Johannes Berg3b3a0162014-05-19 17:19:31 +0200302void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800303{
304 del_timer_sync(&wil->connect_timer);
305 _wil6210_disconnect(wil, bssid);
306}
307
308void wil_priv_deinit(struct wil6210_priv *wil)
309{
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300310 del_timer_sync(&wil->scan_timer);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800311 cancel_work_sync(&wil->disconnect_worker);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200312 cancel_work_sync(&wil->fw_error_worker);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200313 mutex_lock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800314 wil6210_disconnect(wil, NULL);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200315 mutex_unlock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800316 wmi_event_flush(wil);
317 destroy_workqueue(wil->wmi_wq_conn);
318 destroy_workqueue(wil->wmi_wq);
319}
320
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300321/* target operations */
322/* register read */
323#define R(a) ioread32(wil->csr + HOSTADDR(a))
324/* register write. wmb() to make sure it is completed */
325#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
326/* register set = read, OR, write */
327#define S(a, v) W(a, R(a) | v)
328/* register clear = read, AND with inverted, write */
329#define C(a, v) W(a, R(a) & ~v)
330
331static inline void wil_halt_cpu(struct wil6210_priv *wil)
332{
333 W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
334 W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
335}
336
337static inline void wil_release_cpu(struct wil6210_priv *wil)
338{
339 /* Start CPU */
340 W(RGF_USER_USER_CPU_0, 1);
341}
342
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300343static int wil_target_reset(struct wil6210_priv *wil)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800344{
Vladimir Kondratiev98a65b52014-03-17 15:34:12 +0200345 int delay = 0;
Vladimir Kondratievd28bcc32014-03-17 15:34:23 +0200346 u32 hw_state;
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200347 u32 rev_id;
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300348 bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200349
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300350 wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800351
Vladimir Kondratiev17123992014-03-17 15:34:14 +0200352 wil->hw_version = R(RGF_USER_FW_REV_ID);
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200353 rev_id = wil->hw_version & 0xff;
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300354
355 /* Clear MAC link up */
356 S(RGF_HP_CTRL, BIT(15));
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300357 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
358 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
359
360 wil_halt_cpu(wil);
361 C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800362
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300363 if (is_sparrow) {
364 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300365 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300366 }
367
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800368 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
369 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300370 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
371 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800372
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300373 if (is_sparrow) {
374 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300375 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300376 }
377
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800378 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
379 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
380 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
381 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
382
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300383 if (is_sparrow) {
384 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
385 /* reset A2 PCIE AHB */
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200386 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300387 } else {
388 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
389 if (rev_id == 1) {
390 /* reset A1 BOTH PCIE AHB & PCIE RGF */
391 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
392 } else {
393 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
394 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
395 }
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200396 }
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300397
398 /* TODO: check order here!!! Erez code is different */
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800399 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
400
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300401 /* wait until device ready. typical time is 200..250 msec */
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200402 do {
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300403 msleep(RST_DELAY);
Vladimir Kondratievd28bcc32014-03-17 15:34:23 +0200404 hw_state = R(RGF_USER_HW_MACHINE_STATE);
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300405 if (delay++ > RST_COUNT) {
Vladimir Kondratievd28bcc32014-03-17 15:34:23 +0200406 wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
407 hw_state);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300408 return -ETIME;
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200409 }
Vladimir Kondratievd28bcc32014-03-17 15:34:23 +0200410 } while (hw_state != HW_MACHINE_BOOT_DONE);
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200411
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300412 /* TODO: Erez check rev_id != 1 */
413 if (!is_sparrow && (rev_id != 1))
Vladimir Kondratiev17123992014-03-17 15:34:14 +0200414 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200415
Vladimir Kondratiev972072a2014-03-17 15:34:15 +0200416 C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
417
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300418 wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300419 return 0;
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300420}
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800421
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200422#undef R
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800423#undef W
424#undef S
Vladimir Kondratiev972072a2014-03-17 15:34:15 +0200425#undef C
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800426
427void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
428{
429 le32_to_cpus(&r->base);
430 le16_to_cpus(&r->entry_size);
431 le16_to_cpus(&r->size);
432 le32_to_cpus(&r->tail);
433 le32_to_cpus(&r->head);
434}
435
436static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
437{
438 ulong to = msecs_to_jiffies(1000);
439 ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +0300440
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800441 if (0 == left) {
442 wil_err(wil, "Firmware not ready\n");
443 return -ETIME;
444 } else {
Vladimir Kondratiev15e23122014-04-08 11:36:16 +0300445 wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
446 jiffies_to_msecs(to-left), wil->hw_version);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800447 }
448 return 0;
449}
450
451/*
452 * We reset all the structures, and we reset the UMAC.
453 * After calling this routine, you're expected to reload
454 * the firmware.
455 */
456int wil_reset(struct wil6210_priv *wil)
457{
458 int rc;
459
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200460 WARN_ON(!mutex_is_locked(&wil->mutex));
461
462 cancel_work_sync(&wil->disconnect_worker);
463 wil6210_disconnect(wil, NULL);
464
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200465 wil->status = 0; /* prevent NAPI from being scheduled */
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +0300466 if (test_bit(wil_status_napi_en, &wil->status))
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200467 napi_synchronize(&wil->napi_rx);
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200468
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200469 if (wil->scan_request) {
470 wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
471 wil->scan_request);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300472 del_timer_sync(&wil->scan_timer);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200473 cfg80211_scan_done(wil->scan_request, true);
474 wil->scan_request = NULL;
475 }
476
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800477 wil6210_disable_irq(wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800478
Vladimir Kondratieve08b5902013-01-28 18:31:05 +0200479 wmi_event_flush(wil);
480
481 flush_workqueue(wil->wmi_wq_conn);
482 flush_workqueue(wil->wmi_wq);
483
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300484 rc = wil_target_reset(wil);
Vladimir Kondratiev8bf6adb2014-03-17 15:34:17 +0200485 wil_rx_fini(wil);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300486 if (rc)
487 return rc;
488
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300489 if (!no_fw_load) {
490 wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME);
491 wil_halt_cpu(wil);
492 /* Loading f/w from the file */
493 rc = wil_request_firmware(wil, WIL_FW_NAME);
494 if (rc)
495 return rc;
496
497 /* clear any interrupts which on-card-firmware may have set */
498 wil6210_clear_irq(wil);
499 { /* CAF_ICR - clear and mask */
500 u32 a = HOSTADDR(RGF_CAF_ICR) +
501 offsetof(struct RGF_ICR, ICR);
502 u32 m = HOSTADDR(RGF_CAF_ICR) +
503 offsetof(struct RGF_ICR, IMV);
504 u32 icr = ioread32(wil->csr + a);
505
506 iowrite32(icr, wil->csr + a); /* W1C */
507 iowrite32(~0, wil->csr + m);
508 wmb(); /* wait for completion */
509 }
510 wil_release_cpu(wil);
511 } else {
512 wil_info(wil, "Use firmware from on-card flash\n");
513 }
Vladimir Kondratiev8bf6adb2014-03-17 15:34:17 +0200514
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800515 /* init after reset */
516 wil->pending_connect_cid = -1;
Wolfram Sang16735d02013-11-14 14:32:02 -0800517 reinit_completion(&wil->wmi_ready);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800518
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800519 wil6210_enable_irq(wil);
520
521 /* we just started MAC, wait for FW ready */
522 rc = wil_wait_for_fw_ready(wil);
523
524 return rc;
525}
526
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200527void wil_fw_error_recovery(struct wil6210_priv *wil)
528{
529 wil_dbg_misc(wil, "starting fw error recovery\n");
530 schedule_work(&wil->fw_error_worker);
531}
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800532
533void wil_link_on(struct wil6210_priv *wil)
534{
535 struct net_device *ndev = wil_to_ndev(wil);
536
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200537 wil_dbg_misc(wil, "%s()\n", __func__);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800538
539 netif_carrier_on(ndev);
Vladimir Kondratiev55f8f682014-06-16 19:37:23 +0300540 wil_dbg_misc(wil, "netif_tx_wake : link on\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800541 netif_tx_wake_all_queues(ndev);
542}
543
544void wil_link_off(struct wil6210_priv *wil)
545{
546 struct net_device *ndev = wil_to_ndev(wil);
547
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200548 wil_dbg_misc(wil, "%s()\n", __func__);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800549
550 netif_tx_stop_all_queues(ndev);
Vladimir Kondratiev55f8f682014-06-16 19:37:23 +0300551 wil_dbg_misc(wil, "netif_tx_stop : link off\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800552 netif_carrier_off(ndev);
553}
554
555static int __wil_up(struct wil6210_priv *wil)
556{
557 struct net_device *ndev = wil_to_ndev(wil);
558 struct wireless_dev *wdev = wil->wdev;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800559 int rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800560
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200561 WARN_ON(!mutex_is_locked(&wil->mutex));
562
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800563 rc = wil_reset(wil);
564 if (rc)
565 return rc;
566
Vladimir Kondratieve31b2562013-06-09 09:12:55 +0300567 /* Rx VRING. After MAC and beacon */
568 rc = wil_rx_init(wil);
569 if (rc)
570 return rc;
571
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800572 switch (wdev->iftype) {
573 case NL80211_IFTYPE_STATION:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200574 wil_dbg_misc(wil, "type: STATION\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800575 ndev->type = ARPHRD_ETHER;
576 break;
577 case NL80211_IFTYPE_AP:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200578 wil_dbg_misc(wil, "type: AP\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800579 ndev->type = ARPHRD_ETHER;
580 break;
581 case NL80211_IFTYPE_P2P_CLIENT:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200582 wil_dbg_misc(wil, "type: P2P_CLIENT\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800583 ndev->type = ARPHRD_ETHER;
584 break;
585 case NL80211_IFTYPE_P2P_GO:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200586 wil_dbg_misc(wil, "type: P2P_GO\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800587 ndev->type = ARPHRD_ETHER;
588 break;
589 case NL80211_IFTYPE_MONITOR:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200590 wil_dbg_misc(wil, "type: Monitor\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800591 ndev->type = ARPHRD_IEEE80211_RADIOTAP;
592 /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
593 break;
594 default:
595 return -EOPNOTSUPP;
596 }
597
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800598 /* MAC address - pre-requisite for other commands */
599 wmi_set_mac_address(wil, ndev->dev_addr);
600
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800601
Vladimir Kondratieve0287c42013-05-12 14:43:36 +0300602 napi_enable(&wil->napi_rx);
603 napi_enable(&wil->napi_tx);
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200604 set_bit(wil_status_napi_en, &wil->status);
Vladimir Kondratieve0287c42013-05-12 14:43:36 +0300605
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800606 return 0;
607}
608
609int wil_up(struct wil6210_priv *wil)
610{
611 int rc;
612
613 mutex_lock(&wil->mutex);
614 rc = __wil_up(wil);
615 mutex_unlock(&wil->mutex);
616
617 return rc;
618}
619
620static int __wil_down(struct wil6210_priv *wil)
621{
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200622 WARN_ON(!mutex_is_locked(&wil->mutex));
623
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200624 clear_bit(wil_status_napi_en, &wil->status);
Vladimir Kondratieve0287c42013-05-12 14:43:36 +0300625 napi_disable(&wil->napi_rx);
626 napi_disable(&wil->napi_tx);
627
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800628 if (wil->scan_request) {
Vladimir Kondratiev2a91d7d2014-06-16 19:37:11 +0300629 wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
630 wil->scan_request);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300631 del_timer_sync(&wil->scan_timer);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800632 cfg80211_scan_done(wil->scan_request, true);
633 wil->scan_request = NULL;
634 }
635
636 wil6210_disconnect(wil, NULL);
637 wil_rx_fini(wil);
638
639 return 0;
640}
641
642int wil_down(struct wil6210_priv *wil)
643{
644 int rc;
645
646 mutex_lock(&wil->mutex);
647 rc = __wil_down(wil);
648 mutex_unlock(&wil->mutex);
649
650 return rc;
651}
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200652
653int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
654{
655 int i;
656 int rc = -ENOENT;
657
658 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
659 if ((wil->sta[i].status != wil_sta_unused) &&
Vladimir Kondratiev108d1eb2014-02-27 16:20:53 +0200660 ether_addr_equal(wil->sta[i].addr, mac)) {
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200661 rc = i;
662 break;
663 }
664 }
665
666 return rc;
667}