1 | // SPDX-License-Identifier: ISC |
2 | /* |
3 | * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. |
4 | * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. |
5 | */ |
6 | |
7 | #include <linux/etherdevice.h> |
8 | #include <linux/rtnetlink.h> |
9 | #include "wil6210.h" |
10 | #include "txrx.h" |
11 | |
12 | bool wil_has_other_active_ifaces(struct wil6210_priv *wil, |
13 | struct net_device *ndev, bool up, bool ok) |
14 | { |
15 | int i; |
16 | struct wil6210_vif *vif; |
17 | struct net_device *ndev_i; |
18 | |
19 | for (i = 0; i < GET_MAX_VIFS(wil); i++) { |
20 | vif = wil->vifs[i]; |
21 | if (vif) { |
22 | ndev_i = vif_to_ndev(vif); |
23 | if (ndev_i != ndev) |
24 | if ((up && (ndev_i->flags & IFF_UP)) || |
25 | (ok && netif_carrier_ok(dev: ndev_i))) |
26 | return true; |
27 | } |
28 | } |
29 | |
30 | return false; |
31 | } |
32 | |
33 | bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok) |
34 | { |
35 | /* use NULL ndev argument to check all interfaces */ |
36 | return wil_has_other_active_ifaces(wil, NULL, up, ok); |
37 | } |
38 | |
39 | static int wil_open(struct net_device *ndev) |
40 | { |
41 | struct wil6210_priv *wil = ndev_to_wil(ndev); |
42 | int rc = 0; |
43 | |
44 | wil_dbg_misc(wil, "open\n" ); |
45 | |
46 | if (debug_fw || |
47 | test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) { |
48 | wil_err(wil, "while in debug_fw or wmi_only mode\n" ); |
49 | return -EINVAL; |
50 | } |
51 | |
52 | if (!wil_has_other_active_ifaces(wil, ndev, up: true, ok: false)) { |
53 | wil_dbg_misc(wil, "open, first iface\n" ); |
54 | rc = wil_pm_runtime_get(wil); |
55 | if (rc < 0) |
56 | return rc; |
57 | |
58 | rc = wil_up(wil); |
59 | if (rc) |
60 | wil_pm_runtime_put(wil); |
61 | } |
62 | |
63 | return rc; |
64 | } |
65 | |
66 | static int wil_stop(struct net_device *ndev) |
67 | { |
68 | struct wil6210_priv *wil = ndev_to_wil(ndev); |
69 | int rc = 0; |
70 | |
71 | wil_dbg_misc(wil, "stop\n" ); |
72 | |
73 | if (!wil_has_other_active_ifaces(wil, ndev, up: true, ok: false)) { |
74 | wil_dbg_misc(wil, "stop, last iface\n" ); |
75 | rc = wil_down(wil); |
76 | if (!rc) |
77 | wil_pm_runtime_put(wil); |
78 | } |
79 | |
80 | return rc; |
81 | } |
82 | |
83 | static const struct net_device_ops wil_netdev_ops = { |
84 | .ndo_open = wil_open, |
85 | .ndo_stop = wil_stop, |
86 | .ndo_start_xmit = wil_start_xmit, |
87 | .ndo_set_mac_address = eth_mac_addr, |
88 | .ndo_validate_addr = eth_validate_addr, |
89 | }; |
90 | |
91 | static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) |
92 | { |
93 | struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, |
94 | napi_rx); |
95 | int quota = budget; |
96 | int done; |
97 | |
98 | wil_rx_handle(wil, quota: "a); |
99 | done = budget - quota; |
100 | |
101 | if (done < budget) { |
102 | napi_complete_done(n: napi, work_done: done); |
103 | wil6210_unmask_irq_rx(wil); |
104 | wil_dbg_txrx(wil, "NAPI RX complete\n" ); |
105 | } |
106 | |
107 | wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n" , budget, done); |
108 | |
109 | return done; |
110 | } |
111 | |
112 | static int wil6210_netdev_poll_rx_edma(struct napi_struct *napi, int budget) |
113 | { |
114 | struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, |
115 | napi_rx); |
116 | int quota = budget; |
117 | int done; |
118 | |
119 | wil_rx_handle_edma(wil, quota: "a); |
120 | done = budget - quota; |
121 | |
122 | if (done < budget) { |
123 | napi_complete_done(n: napi, work_done: done); |
124 | wil6210_unmask_irq_rx_edma(wil); |
125 | wil_dbg_txrx(wil, "NAPI RX complete\n" ); |
126 | } |
127 | |
128 | wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n" , budget, done); |
129 | |
130 | return done; |
131 | } |
132 | |
133 | static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) |
134 | { |
135 | struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, |
136 | napi_tx); |
137 | int tx_done = 0; |
138 | uint i; |
139 | |
140 | /* always process ALL Tx complete, regardless budget - it is fast */ |
141 | for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { |
142 | struct wil_ring *ring = &wil->ring_tx[i]; |
143 | struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i]; |
144 | struct wil6210_vif *vif; |
145 | |
146 | if (!ring->va || !txdata->enabled || |
147 | txdata->mid >= GET_MAX_VIFS(wil)) |
148 | continue; |
149 | |
150 | vif = wil->vifs[txdata->mid]; |
151 | if (unlikely(!vif)) { |
152 | wil_dbg_txrx(wil, "Invalid MID %d\n" , txdata->mid); |
153 | continue; |
154 | } |
155 | |
156 | tx_done += wil_tx_complete(vif, ringid: i); |
157 | } |
158 | |
159 | if (tx_done < budget) { |
160 | napi_complete(n: napi); |
161 | wil6210_unmask_irq_tx(wil); |
162 | wil_dbg_txrx(wil, "NAPI TX complete\n" ); |
163 | } |
164 | |
165 | wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n" , budget, tx_done); |
166 | |
167 | return min(tx_done, budget); |
168 | } |
169 | |
170 | static int wil6210_netdev_poll_tx_edma(struct napi_struct *napi, int budget) |
171 | { |
172 | struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, |
173 | napi_tx); |
174 | int tx_done; |
175 | /* There is only one status TX ring */ |
176 | struct wil_status_ring *sring = &wil->srings[wil->tx_sring_idx]; |
177 | |
178 | if (!sring->va) |
179 | return 0; |
180 | |
181 | tx_done = wil_tx_sring_handler(wil, sring); |
182 | |
183 | if (tx_done < budget) { |
184 | napi_complete(n: napi); |
185 | wil6210_unmask_irq_tx_edma(wil); |
186 | wil_dbg_txrx(wil, "NAPI TX complete\n" ); |
187 | } |
188 | |
189 | wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n" , budget, tx_done); |
190 | |
191 | return min(tx_done, budget); |
192 | } |
193 | |
194 | static void wil_dev_setup(struct net_device *dev) |
195 | { |
196 | ether_setup(dev); |
197 | dev->max_mtu = mtu_max; |
198 | dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; |
199 | } |
200 | |
201 | static void wil_vif_deinit(struct wil6210_vif *vif) |
202 | { |
203 | del_timer_sync(timer: &vif->scan_timer); |
204 | del_timer_sync(timer: &vif->p2p.discovery_timer); |
205 | cancel_work_sync(work: &vif->disconnect_worker); |
206 | cancel_work_sync(work: &vif->p2p.discovery_expired_work); |
207 | cancel_work_sync(work: &vif->p2p.delayed_listen_work); |
208 | wil_probe_client_flush(vif); |
209 | cancel_work_sync(work: &vif->probe_client_worker); |
210 | cancel_work_sync(work: &vif->enable_tx_key_worker); |
211 | } |
212 | |
213 | void wil_vif_free(struct wil6210_vif *vif) |
214 | { |
215 | struct net_device *ndev = vif_to_ndev(vif); |
216 | |
217 | wil_vif_deinit(vif); |
218 | free_netdev(dev: ndev); |
219 | } |
220 | |
221 | static void wil_ndev_destructor(struct net_device *ndev) |
222 | { |
223 | struct wil6210_vif *vif = ndev_to_vif(ndev); |
224 | |
225 | wil_vif_deinit(vif); |
226 | } |
227 | |
228 | static void wil_connect_timer_fn(struct timer_list *t) |
229 | { |
230 | struct wil6210_vif *vif = from_timer(vif, t, connect_timer); |
231 | struct wil6210_priv *wil = vif_to_wil(vif); |
232 | bool q; |
233 | |
234 | wil_err(wil, "Connect timeout detected, disconnect station\n" ); |
235 | |
236 | /* reschedule to thread context - disconnect won't |
237 | * run from atomic context. |
238 | * queue on wmi_wq to prevent race with connect event. |
239 | */ |
240 | q = queue_work(wq: wil->wmi_wq, work: &vif->disconnect_worker); |
241 | wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n" , q); |
242 | } |
243 | |
244 | static void wil_scan_timer_fn(struct timer_list *t) |
245 | { |
246 | struct wil6210_vif *vif = from_timer(vif, t, scan_timer); |
247 | struct wil6210_priv *wil = vif_to_wil(vif); |
248 | |
249 | clear_bit(nr: wil_status_fwready, addr: wil->status); |
250 | wil_err(wil, "Scan timeout detected, start fw error recovery\n" ); |
251 | wil_fw_error_recovery(wil); |
252 | } |
253 | |
254 | static void wil_p2p_discovery_timer_fn(struct timer_list *t) |
255 | { |
256 | struct wil6210_vif *vif = from_timer(vif, t, p2p.discovery_timer); |
257 | struct wil6210_priv *wil = vif_to_wil(vif); |
258 | |
259 | wil_dbg_misc(wil, "p2p_discovery_timer_fn\n" ); |
260 | |
261 | schedule_work(work: &vif->p2p.discovery_expired_work); |
262 | } |
263 | |
264 | static void wil_vif_init(struct wil6210_vif *vif) |
265 | { |
266 | vif->bcast_ring = -1; |
267 | |
268 | mutex_init(&vif->probe_client_mutex); |
269 | |
270 | timer_setup(&vif->connect_timer, wil_connect_timer_fn, 0); |
271 | timer_setup(&vif->scan_timer, wil_scan_timer_fn, 0); |
272 | timer_setup(&vif->p2p.discovery_timer, wil_p2p_discovery_timer_fn, 0); |
273 | |
274 | INIT_WORK(&vif->probe_client_worker, wil_probe_client_worker); |
275 | INIT_WORK(&vif->disconnect_worker, wil_disconnect_worker); |
276 | INIT_WORK(&vif->p2p.discovery_expired_work, wil_p2p_listen_expired); |
277 | INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work); |
278 | INIT_WORK(&vif->enable_tx_key_worker, wil_enable_tx_key_worker); |
279 | |
280 | INIT_LIST_HEAD(list: &vif->probe_client_pending); |
281 | |
282 | vif->net_queue_stopped = 1; |
283 | } |
284 | |
285 | static u8 wil_vif_find_free_mid(struct wil6210_priv *wil) |
286 | { |
287 | u8 i; |
288 | |
289 | for (i = 0; i < GET_MAX_VIFS(wil); i++) { |
290 | if (!wil->vifs[i]) |
291 | return i; |
292 | } |
293 | |
294 | return U8_MAX; |
295 | } |
296 | |
297 | struct wil6210_vif * |
298 | wil_vif_alloc(struct wil6210_priv *wil, const char *name, |
299 | unsigned char name_assign_type, enum nl80211_iftype iftype) |
300 | { |
301 | struct net_device *ndev; |
302 | struct wireless_dev *wdev; |
303 | struct wil6210_vif *vif; |
304 | u8 mid; |
305 | |
306 | mid = wil_vif_find_free_mid(wil); |
307 | if (mid == U8_MAX) { |
308 | wil_err(wil, "no available virtual interface\n" ); |
309 | return ERR_PTR(error: -EINVAL); |
310 | } |
311 | |
312 | ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, |
313 | wil_dev_setup); |
314 | if (!ndev) { |
315 | dev_err(wil_to_dev(wil), "alloc_netdev failed\n" ); |
316 | return ERR_PTR(error: -ENOMEM); |
317 | } |
318 | if (mid == 0) { |
319 | wil->main_ndev = ndev; |
320 | } else { |
321 | ndev->priv_destructor = wil_ndev_destructor; |
322 | ndev->needs_free_netdev = true; |
323 | } |
324 | |
325 | vif = ndev_to_vif(ndev); |
326 | vif->ndev = ndev; |
327 | vif->wil = wil; |
328 | vif->mid = mid; |
329 | wil_vif_init(vif); |
330 | |
331 | wdev = &vif->wdev; |
332 | wdev->wiphy = wil->wiphy; |
333 | wdev->iftype = iftype; |
334 | |
335 | ndev->netdev_ops = &wil_netdev_ops; |
336 | wil_set_ethtoolops(ndev); |
337 | ndev->ieee80211_ptr = wdev; |
338 | ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | |
339 | NETIF_F_SG | NETIF_F_GRO | |
340 | NETIF_F_TSO | NETIF_F_TSO6; |
341 | |
342 | ndev->features |= ndev->hw_features; |
343 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); |
344 | wdev->netdev = ndev; |
345 | return vif; |
346 | } |
347 | |
348 | void *wil_if_alloc(struct device *dev) |
349 | { |
350 | struct wil6210_priv *wil; |
351 | struct wil6210_vif *vif; |
352 | int rc = 0; |
353 | |
354 | wil = wil_cfg80211_init(dev); |
355 | if (IS_ERR(ptr: wil)) { |
356 | dev_err(dev, "wil_cfg80211_init failed\n" ); |
357 | return wil; |
358 | } |
359 | |
360 | rc = wil_priv_init(wil); |
361 | if (rc) { |
362 | dev_err(dev, "wil_priv_init failed\n" ); |
363 | goto out_cfg; |
364 | } |
365 | |
366 | wil_dbg_misc(wil, "if_alloc\n" ); |
367 | |
368 | vif = wil_vif_alloc(wil, name: "wlan%d" , NET_NAME_UNKNOWN, |
369 | iftype: NL80211_IFTYPE_STATION); |
370 | if (IS_ERR(ptr: vif)) { |
371 | dev_err(dev, "wil_vif_alloc failed\n" ); |
372 | rc = -ENOMEM; |
373 | goto out_priv; |
374 | } |
375 | |
376 | wil->radio_wdev = vif_to_wdev(vif); |
377 | |
378 | return wil; |
379 | |
380 | out_priv: |
381 | wil_priv_deinit(wil); |
382 | |
383 | out_cfg: |
384 | wil_cfg80211_deinit(wil); |
385 | |
386 | return ERR_PTR(error: rc); |
387 | } |
388 | |
389 | void wil_if_free(struct wil6210_priv *wil) |
390 | { |
391 | struct net_device *ndev = wil->main_ndev; |
392 | |
393 | wil_dbg_misc(wil, "if_free\n" ); |
394 | |
395 | if (!ndev) |
396 | return; |
397 | |
398 | wil_priv_deinit(wil); |
399 | |
400 | wil->main_ndev = NULL; |
401 | wil_ndev_destructor(ndev); |
402 | free_netdev(dev: ndev); |
403 | |
404 | wil_cfg80211_deinit(wil); |
405 | } |
406 | |
407 | int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif) |
408 | { |
409 | struct net_device *ndev = vif_to_ndev(vif); |
410 | struct wireless_dev *wdev = vif_to_wdev(vif); |
411 | bool any_active = wil_has_active_ifaces(wil, up: true, ok: false); |
412 | int rc; |
413 | |
414 | ASSERT_RTNL(); |
415 | |
416 | if (wil->vifs[vif->mid]) { |
417 | dev_err(&ndev->dev, "VIF with mid %d already in use\n" , |
418 | vif->mid); |
419 | return -EEXIST; |
420 | } |
421 | if (any_active && vif->mid != 0) { |
422 | rc = wmi_port_allocate(wil, mid: vif->mid, mac: ndev->dev_addr, |
423 | iftype: wdev->iftype); |
424 | if (rc) |
425 | return rc; |
426 | } |
427 | rc = cfg80211_register_netdevice(dev: ndev); |
428 | if (rc < 0) { |
429 | dev_err(&ndev->dev, "Failed to register netdev: %d\n" , rc); |
430 | if (any_active && vif->mid != 0) |
431 | wmi_port_delete(wil, mid: vif->mid); |
432 | return rc; |
433 | } |
434 | |
435 | wil->vifs[vif->mid] = vif; |
436 | return 0; |
437 | } |
438 | |
439 | int wil_if_add(struct wil6210_priv *wil) |
440 | { |
441 | struct wiphy *wiphy = wil->wiphy; |
442 | struct net_device *ndev = wil->main_ndev; |
443 | struct wil6210_vif *vif = ndev_to_vif(ndev); |
444 | int rc; |
445 | |
446 | wil_dbg_misc(wil, "entered" ); |
447 | |
448 | strscpy(wiphy->fw_version, wil->fw_version, sizeof(wiphy->fw_version)); |
449 | |
450 | rc = wiphy_register(wiphy); |
451 | if (rc < 0) { |
452 | wil_err(wil, "failed to register wiphy, err %d\n" , rc); |
453 | return rc; |
454 | } |
455 | |
456 | init_dummy_netdev(dev: &wil->napi_ndev); |
457 | if (wil->use_enhanced_dma_hw) { |
458 | netif_napi_add(dev: &wil->napi_ndev, napi: &wil->napi_rx, |
459 | poll: wil6210_netdev_poll_rx_edma); |
460 | netif_napi_add_tx(dev: &wil->napi_ndev, |
461 | napi: &wil->napi_tx, poll: wil6210_netdev_poll_tx_edma); |
462 | } else { |
463 | netif_napi_add(dev: &wil->napi_ndev, napi: &wil->napi_rx, |
464 | poll: wil6210_netdev_poll_rx); |
465 | netif_napi_add_tx(dev: &wil->napi_ndev, |
466 | napi: &wil->napi_tx, poll: wil6210_netdev_poll_tx); |
467 | } |
468 | |
469 | wil_update_net_queues_bh(wil, vif, NULL, check_stop: true); |
470 | |
471 | rtnl_lock(); |
472 | wiphy_lock(wiphy); |
473 | rc = wil_vif_add(wil, vif); |
474 | wiphy_unlock(wiphy); |
475 | rtnl_unlock(); |
476 | if (rc < 0) |
477 | goto out_wiphy; |
478 | |
479 | return 0; |
480 | |
481 | out_wiphy: |
482 | wiphy_unregister(wiphy); |
483 | return rc; |
484 | } |
485 | |
486 | void wil_vif_remove(struct wil6210_priv *wil, u8 mid) |
487 | { |
488 | struct wil6210_vif *vif; |
489 | struct net_device *ndev; |
490 | bool any_active = wil_has_active_ifaces(wil, up: true, ok: false); |
491 | |
492 | ASSERT_RTNL(); |
493 | if (mid >= GET_MAX_VIFS(wil)) { |
494 | wil_err(wil, "invalid MID: %d\n" , mid); |
495 | return; |
496 | } |
497 | |
498 | vif = wil->vifs[mid]; |
499 | if (!vif) { |
500 | wil_err(wil, "MID %d not registered\n" , mid); |
501 | return; |
502 | } |
503 | |
504 | mutex_lock(&wil->mutex); |
505 | wil6210_disconnect(vif, NULL, reason_code: WLAN_REASON_DEAUTH_LEAVING); |
506 | mutex_unlock(lock: &wil->mutex); |
507 | |
508 | ndev = vif_to_ndev(vif); |
509 | /* during unregister_netdevice cfg80211_leave may perform operations |
510 | * such as stop AP, disconnect, so we only clear the VIF afterwards |
511 | */ |
512 | cfg80211_unregister_netdevice(dev: ndev); |
513 | |
514 | if (any_active && vif->mid != 0) |
515 | wmi_port_delete(wil, mid: vif->mid); |
516 | |
517 | /* make sure no one is accessing the VIF before removing */ |
518 | mutex_lock(&wil->vif_mutex); |
519 | wil->vifs[mid] = NULL; |
520 | /* ensure NAPI code will see the NULL VIF */ |
521 | wmb(); |
522 | if (test_bit(wil_status_napi_en, wil->status)) { |
523 | napi_synchronize(n: &wil->napi_rx); |
524 | napi_synchronize(n: &wil->napi_tx); |
525 | } |
526 | mutex_unlock(lock: &wil->vif_mutex); |
527 | |
528 | flush_work(work: &wil->wmi_event_worker); |
529 | del_timer_sync(timer: &vif->connect_timer); |
530 | cancel_work_sync(work: &vif->disconnect_worker); |
531 | wil_probe_client_flush(vif); |
532 | cancel_work_sync(work: &vif->probe_client_worker); |
533 | cancel_work_sync(work: &vif->enable_tx_key_worker); |
534 | /* for VIFs, ndev will be freed by destructor after RTNL is unlocked. |
535 | * the main interface will be freed in wil_if_free, we need to keep it |
536 | * a bit longer so logging macros will work. |
537 | */ |
538 | } |
539 | |
540 | void wil_if_remove(struct wil6210_priv *wil) |
541 | { |
542 | struct net_device *ndev = wil->main_ndev; |
543 | struct wireless_dev *wdev = ndev->ieee80211_ptr; |
544 | struct wiphy *wiphy = wdev->wiphy; |
545 | |
546 | wil_dbg_misc(wil, "if_remove\n" ); |
547 | |
548 | rtnl_lock(); |
549 | wiphy_lock(wiphy); |
550 | wil_vif_remove(wil, mid: 0); |
551 | wiphy_unlock(wiphy); |
552 | rtnl_unlock(); |
553 | |
554 | netif_napi_del(napi: &wil->napi_tx); |
555 | netif_napi_del(napi: &wil->napi_rx); |
556 | |
557 | wiphy_unregister(wiphy); |
558 | } |
559 | |