blob: 7dfbcfb513378a4040568557e3da0846ba78d7d1 [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 Kondratievfc58f682014-06-16 19:37:16 +030074 wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
75 sta->status);
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +020076
Vladimir Kondratieve58c9f72014-03-17 15:34:06 +020077 sta->data_port_open = false;
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +020078 if (sta->status != wil_sta_unused) {
79 wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
Vladimir Kondratievfc58f682014-06-16 19:37:16 +030080 switch (wdev->iftype) {
81 case NL80211_IFTYPE_AP:
82 case NL80211_IFTYPE_P2P_GO:
83 /* AP-like interface */
84 cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL);
85 break;
86 default:
87 break;
88 }
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +020089 sta->status = wil_sta_unused;
90 }
91
Vladimir Kondratiev91886b02014-02-27 16:20:50 +020092 for (i = 0; i < WIL_STA_TID_NUM; i++) {
93 struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
94 sta->tid_rx[i] = NULL;
95 wil_tid_ampdu_rx_free(wil, r);
96 }
97 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
98 if (wil->vring2cid_tid[i][0] == cid)
99 wil_vring_fini_tx(wil, i);
100 }
101 memset(&sta->stats, 0, sizeof(sta->stats));
102}
103
Johannes Berg3b3a0162014-05-19 17:19:31 +0200104static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800105{
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200106 int cid = -ENOENT;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800107 struct net_device *ndev = wil_to_ndev(wil);
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200108 struct wireless_dev *wdev = wil->wdev;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800109
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200110 might_sleep();
111 if (bssid) {
112 cid = wil_find_cid(wil, bssid);
113 wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
114 } else {
115 wil_dbg_misc(wil, "%s(all)\n", __func__);
116 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800117
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200118 if (cid >= 0) /* disconnect 1 peer */
119 wil_disconnect_cid(wil, cid);
120 else /* disconnect all */
121 for (cid = 0; cid < WIL6210_MAX_CID; cid++)
122 wil_disconnect_cid(wil, cid);
123
124 /* link state */
125 switch (wdev->iftype) {
126 case NL80211_IFTYPE_STATION:
127 case NL80211_IFTYPE_P2P_CLIENT:
128 wil_link_off(wil);
129 if (test_bit(wil_status_fwconnected, &wil->status)) {
130 clear_bit(wil_status_fwconnected, &wil->status);
131 cfg80211_disconnected(ndev,
132 WLAN_STATUS_UNSPECIFIED_FAILURE,
133 NULL, 0, GFP_KERNEL);
134 } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
135 cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
136 WLAN_STATUS_UNSPECIFIED_FAILURE,
137 GFP_KERNEL);
Vladimir Kondratievb4490f42014-02-27 16:20:44 +0200138 }
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200139 clear_bit(wil_status_fwconnecting, &wil->status);
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200140 break;
141 default:
Vladimir Kondratiev91886b02014-02-27 16:20:50 +0200142 break;
Vladimir Kondratievb4490f42014-02-27 16:20:44 +0200143 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800144}
145
146static void wil_disconnect_worker(struct work_struct *work)
147{
148 struct wil6210_priv *wil = container_of(work,
149 struct wil6210_priv, disconnect_worker);
150
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200151 mutex_lock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800152 _wil6210_disconnect(wil, NULL);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200153 mutex_unlock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800154}
155
156static void wil_connect_timer_fn(ulong x)
157{
158 struct wil6210_priv *wil = (void *)x;
159
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200160 wil_dbg_misc(wil, "Connect timeout\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800161
162 /* reschedule to thread context - disconnect won't
163 * run from atomic context
164 */
165 schedule_work(&wil->disconnect_worker);
166}
167
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300168static void wil_scan_timer_fn(ulong x)
169{
170 struct wil6210_priv *wil = (void *)x;
171
172 clear_bit(wil_status_fwready, &wil->status);
173 wil_err(wil, "Scan timeout detected, start fw error recovery\n");
174 schedule_work(&wil->fw_error_worker);
175}
176
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200177static void wil_fw_error_worker(struct work_struct *work)
178{
179 struct wil6210_priv *wil = container_of(work,
180 struct wil6210_priv, fw_error_worker);
181 struct wireless_dev *wdev = wil->wdev;
182
183 wil_dbg_misc(wil, "fw error worker\n");
184
185 if (no_fw_recovery)
186 return;
187
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300188 /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
189 * passed since last recovery attempt
190 */
191 if (time_is_after_jiffies(wil->last_fw_recovery +
192 WIL6210_FW_RECOVERY_TO))
193 wil->recovery_count++;
194 else
195 wil->recovery_count = 1; /* fw was alive for a long time */
196
197 if (wil->recovery_count > WIL6210_FW_RECOVERY_RETRIES) {
198 wil_err(wil, "too many recovery attempts (%d), giving up\n",
199 wil->recovery_count);
200 return;
201 }
202
203 wil->last_fw_recovery = jiffies;
204
Vladimir Kondratiev9c3bde52014-03-17 15:34:21 +0200205 mutex_lock(&wil->mutex);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200206 switch (wdev->iftype) {
207 case NL80211_IFTYPE_STATION:
208 case NL80211_IFTYPE_P2P_CLIENT:
209 case NL80211_IFTYPE_MONITOR:
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300210 wil_info(wil, "fw error recovery started (try %d)...\n",
211 wil->recovery_count);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200212 wil_reset(wil);
213
214 /* need to re-allocate Rx ring after reset */
215 wil_rx_init(wil);
216 break;
217 case NL80211_IFTYPE_AP:
218 case NL80211_IFTYPE_P2P_GO:
219 /* recovery in these modes is done by upper layers */
220 break;
221 default:
222 break;
223 }
Vladimir Kondratiev9c3bde52014-03-17 15:34:21 +0200224 mutex_unlock(&wil->mutex);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200225}
226
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200227static int wil_find_free_vring(struct wil6210_priv *wil)
228{
229 int i;
230 for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
231 if (!wil->vring_tx[i].va)
232 return i;
233 }
234 return -EINVAL;
235}
236
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200237static void wil_connect_worker(struct work_struct *work)
238{
239 int rc;
240 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
241 connect_worker);
242 int cid = wil->pending_connect_cid;
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200243 int ringid = wil_find_free_vring(wil);
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200244
245 if (cid < 0) {
246 wil_err(wil, "No connection pending\n");
247 return;
248 }
249
250 wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
251
Vladimir Kondratiev9a177382014-02-27 16:20:45 +0200252 rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200253 wil->pending_connect_cid = -1;
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200254 if (rc == 0) {
255 wil->sta[cid].status = wil_sta_connected;
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200256 wil_link_on(wil);
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200257 } else {
258 wil->sta[cid].status = wil_sta_unused;
259 }
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200260}
261
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800262int wil_priv_init(struct wil6210_priv *wil)
263{
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200264 wil_dbg_misc(wil, "%s()\n", __func__);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800265
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200266 memset(wil->sta, 0, sizeof(wil->sta));
267
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800268 mutex_init(&wil->mutex);
269 mutex_init(&wil->wmi_mutex);
270
271 init_completion(&wil->wmi_ready);
272
273 wil->pending_connect_cid = -1;
274 setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300275 setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800276
Vladimir Kondratievd81079f2013-03-13 14:12:43 +0200277 INIT_WORK(&wil->connect_worker, wil_connect_worker);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800278 INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
279 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200280 INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800281
282 INIT_LIST_HEAD(&wil->pending_wmi_ev);
283 spin_lock_init(&wil->wmi_ev_lock);
284
285 wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
286 if (!wil->wmi_wq)
287 return -EAGAIN;
288
289 wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
290 if (!wil->wmi_wq_conn) {
291 destroy_workqueue(wil->wmi_wq);
292 return -EAGAIN;
293 }
294
Vladimir Kondratievfc219ee2014-05-27 14:45:45 +0300295 wil->last_fw_recovery = jiffies;
296
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800297 return 0;
298}
299
Johannes Berg3b3a0162014-05-19 17:19:31 +0200300void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800301{
302 del_timer_sync(&wil->connect_timer);
303 _wil6210_disconnect(wil, bssid);
304}
305
306void wil_priv_deinit(struct wil6210_priv *wil)
307{
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300308 del_timer_sync(&wil->scan_timer);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800309 cancel_work_sync(&wil->disconnect_worker);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200310 cancel_work_sync(&wil->fw_error_worker);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200311 mutex_lock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800312 wil6210_disconnect(wil, NULL);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200313 mutex_unlock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800314 wmi_event_flush(wil);
315 destroy_workqueue(wil->wmi_wq_conn);
316 destroy_workqueue(wil->wmi_wq);
317}
318
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300319/* target operations */
320/* register read */
321#define R(a) ioread32(wil->csr + HOSTADDR(a))
322/* register write. wmb() to make sure it is completed */
323#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
324/* register set = read, OR, write */
325#define S(a, v) W(a, R(a) | v)
326/* register clear = read, AND with inverted, write */
327#define C(a, v) W(a, R(a) & ~v)
328
329static inline void wil_halt_cpu(struct wil6210_priv *wil)
330{
331 W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
332 W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
333}
334
335static inline void wil_release_cpu(struct wil6210_priv *wil)
336{
337 /* Start CPU */
338 W(RGF_USER_USER_CPU_0, 1);
339}
340
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300341static int wil_target_reset(struct wil6210_priv *wil)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800342{
Vladimir Kondratiev98a65b52014-03-17 15:34:12 +0200343 int delay = 0;
Vladimir Kondratievd28bcc32014-03-17 15:34:23 +0200344 u32 hw_state;
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200345 u32 rev_id;
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300346 bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200347
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300348 wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800349
Vladimir Kondratiev17123992014-03-17 15:34:14 +0200350 wil->hw_version = R(RGF_USER_FW_REV_ID);
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200351 rev_id = wil->hw_version & 0xff;
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300352
353 /* Clear MAC link up */
354 S(RGF_HP_CTRL, BIT(15));
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300355 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
356 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
357
358 wil_halt_cpu(wil);
359 C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800360
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300361 if (is_sparrow) {
362 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300363 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300364 }
365
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800366 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
367 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300368 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
369 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800370
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300371 if (is_sparrow) {
372 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300373 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300374 }
375
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800376 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
377 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
378 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
379 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
380
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300381 if (is_sparrow) {
382 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
383 /* reset A2 PCIE AHB */
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200384 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300385 } else {
386 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
387 if (rev_id == 1) {
388 /* reset A1 BOTH PCIE AHB & PCIE RGF */
389 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
390 } else {
391 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
392 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
393 }
394
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200395 }
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300396
397 /* TODO: check order here!!! Erez code is different */
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800398 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
399
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300400 /* wait until device ready. typical time is 200..250 msec */
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200401 do {
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300402 msleep(RST_DELAY);
Vladimir Kondratievd28bcc32014-03-17 15:34:23 +0200403 hw_state = R(RGF_USER_HW_MACHINE_STATE);
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300404 if (delay++ > RST_COUNT) {
Vladimir Kondratievd28bcc32014-03-17 15:34:23 +0200405 wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
406 hw_state);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300407 return -ETIME;
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200408 }
Vladimir Kondratievd28bcc32014-03-17 15:34:23 +0200409 } while (hw_state != HW_MACHINE_BOOT_DONE);
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200410
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300411 /* TODO: Erez check rev_id != 1 */
412 if (!is_sparrow && (rev_id != 1))
Vladimir Kondratiev17123992014-03-17 15:34:14 +0200413 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200414
Vladimir Kondratiev972072a2014-03-17 15:34:15 +0200415 C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
416
Vladimir Kondratiev520d68e2014-08-06 10:31:53 +0300417 wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300418 return 0;
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300419}
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800420
Vladimir Kondratiev36b10a72014-03-17 15:34:10 +0200421#undef R
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800422#undef W
423#undef S
Vladimir Kondratiev972072a2014-03-17 15:34:15 +0200424#undef C
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800425
426void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
427{
428 le32_to_cpus(&r->base);
429 le16_to_cpus(&r->entry_size);
430 le16_to_cpus(&r->size);
431 le32_to_cpus(&r->tail);
432 le32_to_cpus(&r->head);
433}
434
435static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
436{
437 ulong to = msecs_to_jiffies(1000);
438 ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
439 if (0 == left) {
440 wil_err(wil, "Firmware not ready\n");
441 return -ETIME;
442 } else {
Vladimir Kondratiev15e23122014-04-08 11:36:16 +0300443 wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
444 jiffies_to_msecs(to-left), wil->hw_version);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800445 }
446 return 0;
447}
448
449/*
450 * We reset all the structures, and we reset the UMAC.
451 * After calling this routine, you're expected to reload
452 * the firmware.
453 */
454int wil_reset(struct wil6210_priv *wil)
455{
456 int rc;
457
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200458 WARN_ON(!mutex_is_locked(&wil->mutex));
459
460 cancel_work_sync(&wil->disconnect_worker);
461 wil6210_disconnect(wil, NULL);
462
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200463 wil->status = 0; /* prevent NAPI from being scheduled */
464 if (test_bit(wil_status_napi_en, &wil->status)) {
465 napi_synchronize(&wil->napi_rx);
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200466 }
467
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200468 if (wil->scan_request) {
469 wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
470 wil->scan_request);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300471 del_timer_sync(&wil->scan_timer);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200472 cfg80211_scan_done(wil->scan_request, true);
473 wil->scan_request = NULL;
474 }
475
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800476 wil6210_disable_irq(wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800477
Vladimir Kondratieve08b5902013-01-28 18:31:05 +0200478 wmi_event_flush(wil);
479
480 flush_workqueue(wil->wmi_wq_conn);
481 flush_workqueue(wil->wmi_wq);
482
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300483 rc = wil_target_reset(wil);
Vladimir Kondratiev8bf6adb2014-03-17 15:34:17 +0200484 wil_rx_fini(wil);
Vladimir Kondratievbbb2adc2014-08-06 10:31:52 +0300485 if (rc)
486 return rc;
487
Vladimir Kondratiev151a9702014-09-10 16:34:30 +0300488 if (!no_fw_load) {
489 wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME);
490 wil_halt_cpu(wil);
491 /* Loading f/w from the file */
492 rc = wil_request_firmware(wil, WIL_FW_NAME);
493 if (rc)
494 return rc;
495
496 /* clear any interrupts which on-card-firmware may have set */
497 wil6210_clear_irq(wil);
498 { /* CAF_ICR - clear and mask */
499 u32 a = HOSTADDR(RGF_CAF_ICR) +
500 offsetof(struct RGF_ICR, ICR);
501 u32 m = HOSTADDR(RGF_CAF_ICR) +
502 offsetof(struct RGF_ICR, IMV);
503 u32 icr = ioread32(wil->csr + a);
504
505 iowrite32(icr, wil->csr + a); /* W1C */
506 iowrite32(~0, wil->csr + m);
507 wmb(); /* wait for completion */
508 }
509 wil_release_cpu(wil);
510 } else {
511 wil_info(wil, "Use firmware from on-card flash\n");
512 }
Vladimir Kondratiev8bf6adb2014-03-17 15:34:17 +0200513
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800514 /* init after reset */
515 wil->pending_connect_cid = -1;
Wolfram Sang16735d02013-11-14 14:32:02 -0800516 reinit_completion(&wil->wmi_ready);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800517
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800518 wil6210_enable_irq(wil);
519
520 /* we just started MAC, wait for FW ready */
521 rc = wil_wait_for_fw_ready(wil);
522
523 return rc;
524}
525
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200526void wil_fw_error_recovery(struct wil6210_priv *wil)
527{
528 wil_dbg_misc(wil, "starting fw error recovery\n");
529 schedule_work(&wil->fw_error_worker);
530}
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800531
532void wil_link_on(struct wil6210_priv *wil)
533{
534 struct net_device *ndev = wil_to_ndev(wil);
535
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200536 wil_dbg_misc(wil, "%s()\n", __func__);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800537
538 netif_carrier_on(ndev);
Vladimir Kondratiev55f8f682014-06-16 19:37:23 +0300539 wil_dbg_misc(wil, "netif_tx_wake : link on\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800540 netif_tx_wake_all_queues(ndev);
541}
542
543void wil_link_off(struct wil6210_priv *wil)
544{
545 struct net_device *ndev = wil_to_ndev(wil);
546
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200547 wil_dbg_misc(wil, "%s()\n", __func__);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800548
549 netif_tx_stop_all_queues(ndev);
Vladimir Kondratiev55f8f682014-06-16 19:37:23 +0300550 wil_dbg_misc(wil, "netif_tx_stop : link off\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800551 netif_carrier_off(ndev);
552}
553
554static int __wil_up(struct wil6210_priv *wil)
555{
556 struct net_device *ndev = wil_to_ndev(wil);
557 struct wireless_dev *wdev = wil->wdev;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800558 int rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800559
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200560 WARN_ON(!mutex_is_locked(&wil->mutex));
561
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800562 rc = wil_reset(wil);
563 if (rc)
564 return rc;
565
Vladimir Kondratieve31b2562013-06-09 09:12:55 +0300566 /* Rx VRING. After MAC and beacon */
567 rc = wil_rx_init(wil);
568 if (rc)
569 return rc;
570
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800571 switch (wdev->iftype) {
572 case NL80211_IFTYPE_STATION:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200573 wil_dbg_misc(wil, "type: STATION\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800574 ndev->type = ARPHRD_ETHER;
575 break;
576 case NL80211_IFTYPE_AP:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200577 wil_dbg_misc(wil, "type: AP\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800578 ndev->type = ARPHRD_ETHER;
579 break;
580 case NL80211_IFTYPE_P2P_CLIENT:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200581 wil_dbg_misc(wil, "type: P2P_CLIENT\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800582 ndev->type = ARPHRD_ETHER;
583 break;
584 case NL80211_IFTYPE_P2P_GO:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200585 wil_dbg_misc(wil, "type: P2P_GO\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800586 ndev->type = ARPHRD_ETHER;
587 break;
588 case NL80211_IFTYPE_MONITOR:
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200589 wil_dbg_misc(wil, "type: Monitor\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800590 ndev->type = ARPHRD_IEEE80211_RADIOTAP;
591 /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
592 break;
593 default:
594 return -EOPNOTSUPP;
595 }
596
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800597 /* MAC address - pre-requisite for other commands */
598 wmi_set_mac_address(wil, ndev->dev_addr);
599
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800600
Vladimir Kondratieve0287c42013-05-12 14:43:36 +0300601 napi_enable(&wil->napi_rx);
602 napi_enable(&wil->napi_tx);
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200603 set_bit(wil_status_napi_en, &wil->status);
Vladimir Kondratieve0287c42013-05-12 14:43:36 +0300604
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800605 return 0;
606}
607
608int wil_up(struct wil6210_priv *wil)
609{
610 int rc;
611
612 mutex_lock(&wil->mutex);
613 rc = __wil_up(wil);
614 mutex_unlock(&wil->mutex);
615
616 return rc;
617}
618
619static int __wil_down(struct wil6210_priv *wil)
620{
Vladimir Kondratiev097638a2014-03-17 15:34:25 +0200621 WARN_ON(!mutex_is_locked(&wil->mutex));
622
Vladimir Kondratiev0fef1812014-03-17 15:34:18 +0200623 clear_bit(wil_status_napi_en, &wil->status);
Vladimir Kondratieve0287c42013-05-12 14:43:36 +0300624 napi_disable(&wil->napi_rx);
625 napi_disable(&wil->napi_tx);
626
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800627 if (wil->scan_request) {
Vladimir Kondratiev2a91d7d2014-06-16 19:37:11 +0300628 wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
629 wil->scan_request);
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300630 del_timer_sync(&wil->scan_timer);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800631 cfg80211_scan_done(wil->scan_request, true);
632 wil->scan_request = NULL;
633 }
634
635 wil6210_disconnect(wil, NULL);
636 wil_rx_fini(wil);
637
638 return 0;
639}
640
641int wil_down(struct wil6210_priv *wil)
642{
643 int rc;
644
645 mutex_lock(&wil->mutex);
646 rc = __wil_down(wil);
647 mutex_unlock(&wil->mutex);
648
649 return rc;
650}
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200651
652int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
653{
654 int i;
655 int rc = -ENOENT;
656
657 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
658 if ((wil->sta[i].status != wil_sta_unused) &&
Vladimir Kondratiev108d1eb2014-02-27 16:20:53 +0200659 ether_addr_equal(wil->sta[i].addr, mac)) {
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200660 rc = i;
661 break;
662 }
663 }
664
665 return rc;
666}