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