aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/wil6210/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/main.c')
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c234
1 files changed, 210 insertions, 24 deletions
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index fd30cddd5882..95f4efe9ef37 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -16,8 +16,14 @@
16 16
17#include <linux/moduleparam.h> 17#include <linux/moduleparam.h>
18#include <linux/if_arp.h> 18#include <linux/if_arp.h>
19#include <linux/etherdevice.h>
19 20
20#include "wil6210.h" 21#include "wil6210.h"
22#include "txrx.h"
23
24static bool no_fw_recovery;
25module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
26MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
21 27
22/* 28/*
23 * Due to a hardware issue, 29 * Due to a hardware issue,
@@ -52,29 +58,74 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
52 __raw_writel(*s++, d++); 58 __raw_writel(*s++, d++);
53} 59}
54 60
55static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) 61static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
56{ 62{
57 uint i; 63 uint i;
58 struct net_device *ndev = wil_to_ndev(wil); 64 struct wil_sta_info *sta = &wil->sta[cid];
59 65
60 wil_dbg_misc(wil, "%s()\n", __func__); 66 sta->data_port_open = false;
67 if (sta->status != wil_sta_unused) {
68 wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
69 sta->status = wil_sta_unused;
70 }
61 71
62 wil_link_off(wil); 72 for (i = 0; i < WIL_STA_TID_NUM; i++) {
63 if (test_bit(wil_status_fwconnected, &wil->status)) { 73 struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
64 clear_bit(wil_status_fwconnected, &wil->status); 74 sta->tid_rx[i] = NULL;
65 cfg80211_disconnected(ndev, 75 wil_tid_ampdu_rx_free(wil, r);
66 WLAN_STATUS_UNSPECIFIED_FAILURE, 76 }
67 NULL, 0, GFP_KERNEL); 77 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
68 } else if (test_bit(wil_status_fwconnecting, &wil->status)) { 78 if (wil->vring2cid_tid[i][0] == cid)
69 cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, 79 wil_vring_fini_tx(wil, i);
70 WLAN_STATUS_UNSPECIFIED_FAILURE,
71 GFP_KERNEL);
72 } 80 }
73 clear_bit(wil_status_fwconnecting, &wil->status); 81 memset(&sta->stats, 0, sizeof(sta->stats));
74 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) 82}
75 wil_vring_fini_tx(wil, i);
76 83
77 clear_bit(wil_status_dontscan, &wil->status); 84static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
85{
86 int cid = -ENOENT;
87 struct net_device *ndev = wil_to_ndev(wil);
88 struct wireless_dev *wdev = wil->wdev;
89
90 might_sleep();
91 if (bssid) {
92 cid = wil_find_cid(wil, bssid);
93 wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
94 } else {
95 wil_dbg_misc(wil, "%s(all)\n", __func__);
96 }
97
98 if (cid >= 0) /* disconnect 1 peer */
99 wil_disconnect_cid(wil, cid);
100 else /* disconnect all */
101 for (cid = 0; cid < WIL6210_MAX_CID; cid++)
102 wil_disconnect_cid(wil, cid);
103
104 /* link state */
105 switch (wdev->iftype) {
106 case NL80211_IFTYPE_STATION:
107 case NL80211_IFTYPE_P2P_CLIENT:
108 wil_link_off(wil);
109 if (test_bit(wil_status_fwconnected, &wil->status)) {
110 clear_bit(wil_status_fwconnected, &wil->status);
111 cfg80211_disconnected(ndev,
112 WLAN_STATUS_UNSPECIFIED_FAILURE,
113 NULL, 0, GFP_KERNEL);
114 } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
115 cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
116 WLAN_STATUS_UNSPECIFIED_FAILURE,
117 GFP_KERNEL);
118 }
119 clear_bit(wil_status_fwconnecting, &wil->status);
120 break;
121 default:
122 /* AP-like interface and monitor:
123 * never scan, always connected
124 */
125 if (bssid)
126 cfg80211_del_sta(ndev, bssid, GFP_KERNEL);
127 break;
128 }
78} 129}
79 130
80static void wil_disconnect_worker(struct work_struct *work) 131static void wil_disconnect_worker(struct work_struct *work)
@@ -82,7 +133,9 @@ static void wil_disconnect_worker(struct work_struct *work)
82 struct wil6210_priv *wil = container_of(work, 133 struct wil6210_priv *wil = container_of(work,
83 struct wil6210_priv, disconnect_worker); 134 struct wil6210_priv, disconnect_worker);
84 135
136 mutex_lock(&wil->mutex);
85 _wil6210_disconnect(wil, NULL); 137 _wil6210_disconnect(wil, NULL);
138 mutex_unlock(&wil->mutex);
86} 139}
87 140
88static void wil_connect_timer_fn(ulong x) 141static void wil_connect_timer_fn(ulong x)
@@ -97,12 +150,55 @@ static void wil_connect_timer_fn(ulong x)
97 schedule_work(&wil->disconnect_worker); 150 schedule_work(&wil->disconnect_worker);
98} 151}
99 152
153static void wil_fw_error_worker(struct work_struct *work)
154{
155 struct wil6210_priv *wil = container_of(work,
156 struct wil6210_priv, fw_error_worker);
157 struct wireless_dev *wdev = wil->wdev;
158
159 wil_dbg_misc(wil, "fw error worker\n");
160
161 if (no_fw_recovery)
162 return;
163
164 mutex_lock(&wil->mutex);
165 switch (wdev->iftype) {
166 case NL80211_IFTYPE_STATION:
167 case NL80211_IFTYPE_P2P_CLIENT:
168 case NL80211_IFTYPE_MONITOR:
169 wil_info(wil, "fw error recovery started...\n");
170 wil_reset(wil);
171
172 /* need to re-allocate Rx ring after reset */
173 wil_rx_init(wil);
174 break;
175 case NL80211_IFTYPE_AP:
176 case NL80211_IFTYPE_P2P_GO:
177 /* recovery in these modes is done by upper layers */
178 break;
179 default:
180 break;
181 }
182 mutex_unlock(&wil->mutex);
183}
184
185static int wil_find_free_vring(struct wil6210_priv *wil)
186{
187 int i;
188 for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
189 if (!wil->vring_tx[i].va)
190 return i;
191 }
192 return -EINVAL;
193}
194
100static void wil_connect_worker(struct work_struct *work) 195static void wil_connect_worker(struct work_struct *work)
101{ 196{
102 int rc; 197 int rc;
103 struct wil6210_priv *wil = container_of(work, struct wil6210_priv, 198 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
104 connect_worker); 199 connect_worker);
105 int cid = wil->pending_connect_cid; 200 int cid = wil->pending_connect_cid;
201 int ringid = wil_find_free_vring(wil);
106 202
107 if (cid < 0) { 203 if (cid < 0) {
108 wil_err(wil, "No connection pending\n"); 204 wil_err(wil, "No connection pending\n");
@@ -111,16 +207,22 @@ static void wil_connect_worker(struct work_struct *work)
111 207
112 wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid); 208 wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
113 209
114 rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0); 210 rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
115 wil->pending_connect_cid = -1; 211 wil->pending_connect_cid = -1;
116 if (rc == 0) 212 if (rc == 0) {
213 wil->sta[cid].status = wil_sta_connected;
117 wil_link_on(wil); 214 wil_link_on(wil);
215 } else {
216 wil->sta[cid].status = wil_sta_unused;
217 }
118} 218}
119 219
120int wil_priv_init(struct wil6210_priv *wil) 220int wil_priv_init(struct wil6210_priv *wil)
121{ 221{
122 wil_dbg_misc(wil, "%s()\n", __func__); 222 wil_dbg_misc(wil, "%s()\n", __func__);
123 223
224 memset(wil->sta, 0, sizeof(wil->sta));
225
124 mutex_init(&wil->mutex); 226 mutex_init(&wil->mutex);
125 mutex_init(&wil->wmi_mutex); 227 mutex_init(&wil->wmi_mutex);
126 228
@@ -132,6 +234,7 @@ int wil_priv_init(struct wil6210_priv *wil)
132 INIT_WORK(&wil->connect_worker, wil_connect_worker); 234 INIT_WORK(&wil->connect_worker, wil_connect_worker);
133 INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); 235 INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
134 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); 236 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
237 INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
135 238
136 INIT_LIST_HEAD(&wil->pending_wmi_ev); 239 INIT_LIST_HEAD(&wil->pending_wmi_ev);
137 spin_lock_init(&wil->wmi_ev_lock); 240 spin_lock_init(&wil->wmi_ev_lock);
@@ -158,7 +261,10 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
158void wil_priv_deinit(struct wil6210_priv *wil) 261void wil_priv_deinit(struct wil6210_priv *wil)
159{ 262{
160 cancel_work_sync(&wil->disconnect_worker); 263 cancel_work_sync(&wil->disconnect_worker);
264 cancel_work_sync(&wil->fw_error_worker);
265 mutex_lock(&wil->mutex);
161 wil6210_disconnect(wil, NULL); 266 wil6210_disconnect(wil, NULL);
267 mutex_unlock(&wil->mutex);
162 wmi_event_flush(wil); 268 wmi_event_flush(wil);
163 destroy_workqueue(wil->wmi_wq_conn); 269 destroy_workqueue(wil->wmi_wq_conn);
164 destroy_workqueue(wil->wmi_wq); 270 destroy_workqueue(wil->wmi_wq);
@@ -166,40 +272,78 @@ void wil_priv_deinit(struct wil6210_priv *wil)
166 272
167static void wil_target_reset(struct wil6210_priv *wil) 273static void wil_target_reset(struct wil6210_priv *wil)
168{ 274{
275 int delay = 0;
276 u32 hw_state;
277 u32 rev_id;
278
169 wil_dbg_misc(wil, "Resetting...\n"); 279 wil_dbg_misc(wil, "Resetting...\n");
170 280
281 /* register read */
282#define R(a) ioread32(wil->csr + HOSTADDR(a))
171 /* register write */ 283 /* register write */
172#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) 284#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
173 /* register set = read, OR, write */ 285 /* register set = read, OR, write */
174#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ 286#define S(a, v) W(a, R(a) | v)
175 wil->csr + HOSTADDR(a)) 287 /* register clear = read, AND with inverted, write */
288#define C(a, v) W(a, R(a) & ~v)
176 289
290 wil->hw_version = R(RGF_USER_FW_REV_ID);
291 rev_id = wil->hw_version & 0xff;
177 /* hpal_perst_from_pad_src_n_mask */ 292 /* hpal_perst_from_pad_src_n_mask */
178 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); 293 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
179 /* car_perst_rst_src_n_mask */ 294 /* car_perst_rst_src_n_mask */
180 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); 295 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
296 wmb(); /* order is important here */
181 297
182 W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ 298 W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
183 W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ 299 W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
300 wmb(); /* order is important here */
184 301
185 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); 302 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
186 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); 303 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
187 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); 304 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
188 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); 305 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
306 wmb(); /* order is important here */
189 307
190 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); 308 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
191 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); 309 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
192 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); 310 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
193 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); 311 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
312 wmb(); /* order is important here */
194 313
195 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); 314 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
196 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); 315 if (rev_id == 1) {
316 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
317 } else {
318 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
319 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
320 }
197 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); 321 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
322 wmb(); /* order is important here */
323
324 /* wait until device ready */
325 do {
326 msleep(1);
327 hw_state = R(RGF_USER_HW_MACHINE_STATE);
328 if (delay++ > 100) {
329 wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
330 hw_state);
331 return;
332 }
333 } while (hw_state != HW_MACHINE_BOOT_DONE);
334
335 if (rev_id == 2)
336 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
337
338 C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
339 wmb(); /* order is important here */
198 340
199 wil_dbg_misc(wil, "Reset completed\n"); 341 wil_dbg_misc(wil, "Reset completed in %d ms\n", delay);
200 342
343#undef R
201#undef W 344#undef W
202#undef S 345#undef S
346#undef C
203} 347}
204 348
205void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) 349void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
@@ -234,11 +378,24 @@ int wil_reset(struct wil6210_priv *wil)
234{ 378{
235 int rc; 379 int rc;
236 380
381 WARN_ON(!mutex_is_locked(&wil->mutex));
382
237 cancel_work_sync(&wil->disconnect_worker); 383 cancel_work_sync(&wil->disconnect_worker);
238 wil6210_disconnect(wil, NULL); 384 wil6210_disconnect(wil, NULL);
239 385
386 wil->status = 0; /* prevent NAPI from being scheduled */
387 if (test_bit(wil_status_napi_en, &wil->status)) {
388 napi_synchronize(&wil->napi_rx);
389 }
390
391 if (wil->scan_request) {
392 wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
393 wil->scan_request);
394 cfg80211_scan_done(wil->scan_request, true);
395 wil->scan_request = NULL;
396 }
397
240 wil6210_disable_irq(wil); 398 wil6210_disable_irq(wil);
241 wil->status = 0;
242 399
243 wmi_event_flush(wil); 400 wmi_event_flush(wil);
244 401
@@ -248,6 +405,8 @@ int wil_reset(struct wil6210_priv *wil)
248 /* TODO: put MAC in reset */ 405 /* TODO: put MAC in reset */
249 wil_target_reset(wil); 406 wil_target_reset(wil);
250 407
408 wil_rx_fini(wil);
409
251 /* init after reset */ 410 /* init after reset */
252 wil->pending_connect_cid = -1; 411 wil->pending_connect_cid = -1;
253 reinit_completion(&wil->wmi_ready); 412 reinit_completion(&wil->wmi_ready);
@@ -261,6 +420,11 @@ int wil_reset(struct wil6210_priv *wil)
261 return rc; 420 return rc;
262} 421}
263 422
423void wil_fw_error_recovery(struct wil6210_priv *wil)
424{
425 wil_dbg_misc(wil, "starting fw error recovery\n");
426 schedule_work(&wil->fw_error_worker);
427}
264 428
265void wil_link_on(struct wil6210_priv *wil) 429void wil_link_on(struct wil6210_priv *wil)
266{ 430{
@@ -288,6 +452,8 @@ static int __wil_up(struct wil6210_priv *wil)
288 struct wireless_dev *wdev = wil->wdev; 452 struct wireless_dev *wdev = wil->wdev;
289 int rc; 453 int rc;
290 454
455 WARN_ON(!mutex_is_locked(&wil->mutex));
456
291 rc = wil_reset(wil); 457 rc = wil_reset(wil);
292 if (rc) 458 if (rc)
293 return rc; 459 return rc;
@@ -329,6 +495,7 @@ static int __wil_up(struct wil6210_priv *wil)
329 495
330 napi_enable(&wil->napi_rx); 496 napi_enable(&wil->napi_rx);
331 napi_enable(&wil->napi_tx); 497 napi_enable(&wil->napi_tx);
498 set_bit(wil_status_napi_en, &wil->status);
332 499
333 return 0; 500 return 0;
334} 501}
@@ -346,6 +513,9 @@ int wil_up(struct wil6210_priv *wil)
346 513
347static int __wil_down(struct wil6210_priv *wil) 514static int __wil_down(struct wil6210_priv *wil)
348{ 515{
516 WARN_ON(!mutex_is_locked(&wil->mutex));
517
518 clear_bit(wil_status_napi_en, &wil->status);
349 napi_disable(&wil->napi_rx); 519 napi_disable(&wil->napi_rx);
350 napi_disable(&wil->napi_tx); 520 napi_disable(&wil->napi_tx);
351 521
@@ -370,3 +540,19 @@ int wil_down(struct wil6210_priv *wil)
370 540
371 return rc; 541 return rc;
372} 542}
543
544int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
545{
546 int i;
547 int rc = -ENOENT;
548
549 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
550 if ((wil->sta[i].status != wil_sta_unused) &&
551 ether_addr_equal(wil->sta[i].addr, mac)) {
552 rc = i;
553 break;
554 }
555 }
556
557 return rc;
558}