brintos

brintos / linux-shallow public Read only

0
0
Text · 13.0 KiB · d5d3646 Raw
568 lines · c
1// SPDX-License-Identifier: ISC2/*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 12bool 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(ndev_i)))26					return true;27		}28	}29 30	return false;31}32 33bool 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 39static 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, true, 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 66static 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, true, 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 83static 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 91static 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);99	done = budget - quota;100 101	if (done < budget) {102		napi_complete_done(napi, 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 112static 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);120	done = budget - quota;121 122	if (done < budget) {123		napi_complete_done(napi, 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 133static 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, i);157	}158 159	if (tx_done < budget) {160		napi_complete(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 170static 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(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 194static 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 201static void wil_vif_deinit(struct wil6210_vif *vif)202{203	del_timer_sync(&vif->scan_timer);204	del_timer_sync(&vif->p2p.discovery_timer);205	cancel_work_sync(&vif->disconnect_worker);206	cancel_work_sync(&vif->p2p.discovery_expired_work);207	cancel_work_sync(&vif->p2p.delayed_listen_work);208	wil_probe_client_flush(vif);209	cancel_work_sync(&vif->probe_client_worker);210	cancel_work_sync(&vif->enable_tx_key_worker);211}212 213void 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(ndev);219}220 221static 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 228static 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't237	 * run from atomic context.238	 * queue on wmi_wq to prevent race with connect event.239	 */240	q = queue_work(wil->wmi_wq, &vif->disconnect_worker);241	wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q);242}243 244static 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(wil_status_fwready, wil->status);250	wil_err(wil, "Scan timeout detected, start fw error recovery\n");251	wil_fw_error_recovery(wil);252}253 254static 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(&vif->p2p.discovery_expired_work);262}263 264static 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(&vif->probe_client_pending);281 282	vif->net_queue_stopped = 1;283}284 285static 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 297struct wil6210_vif *298wil_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(-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(-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 348void *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(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, "wlan%d", NET_NAME_UNKNOWN,369			    NL80211_IFTYPE_STATION);370	if (IS_ERR(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 380out_priv:381	wil_priv_deinit(wil);382 383out_cfg:384	wil_cfg80211_deinit(wil);385 386	return ERR_PTR(rc);387}388 389void 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(ndev);403 404	wil_cfg80211_deinit(wil);405}406 407int 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, true, 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, vif->mid, ndev->dev_addr,423				       wdev->iftype);424		if (rc)425			return rc;426	}427	rc = cfg80211_register_netdevice(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, vif->mid);432		return rc;433	}434 435	wil->vifs[vif->mid] = vif;436	return 0;437}438 439int 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	wil->napi_ndev = alloc_netdev_dummy(0);457	if (!wil->napi_ndev) {458		wil_err(wil, "failed to allocate dummy netdev");459		rc = -ENOMEM;460		goto out_wiphy;461	}462	if (wil->use_enhanced_dma_hw) {463		netif_napi_add(wil->napi_ndev, &wil->napi_rx,464			       wil6210_netdev_poll_rx_edma);465		netif_napi_add_tx(wil->napi_ndev,466				  &wil->napi_tx, wil6210_netdev_poll_tx_edma);467	} else {468		netif_napi_add(wil->napi_ndev, &wil->napi_rx,469			       wil6210_netdev_poll_rx);470		netif_napi_add_tx(wil->napi_ndev,471				  &wil->napi_tx, wil6210_netdev_poll_tx);472	}473 474	wil_update_net_queues_bh(wil, vif, NULL, true);475 476	rtnl_lock();477	wiphy_lock(wiphy);478	rc = wil_vif_add(wil, vif);479	wiphy_unlock(wiphy);480	rtnl_unlock();481	if (rc < 0)482		goto free_dummy;483 484	return 0;485 486free_dummy:487	free_netdev(wil->napi_ndev);488out_wiphy:489	wiphy_unregister(wiphy);490	return rc;491}492 493void wil_vif_remove(struct wil6210_priv *wil, u8 mid)494{495	struct wil6210_vif *vif;496	struct net_device *ndev;497	bool any_active = wil_has_active_ifaces(wil, true, false);498 499	ASSERT_RTNL();500	if (mid >= GET_MAX_VIFS(wil)) {501		wil_err(wil, "invalid MID: %d\n", mid);502		return;503	}504 505	vif = wil->vifs[mid];506	if (!vif) {507		wil_err(wil, "MID %d not registered\n", mid);508		return;509	}510 511	mutex_lock(&wil->mutex);512	wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING);513	mutex_unlock(&wil->mutex);514 515	ndev = vif_to_ndev(vif);516	/* during unregister_netdevice cfg80211_leave may perform operations517	 * such as stop AP, disconnect, so we only clear the VIF afterwards518	 */519	cfg80211_unregister_netdevice(ndev);520 521	if (any_active && vif->mid != 0)522		wmi_port_delete(wil, vif->mid);523 524	/* make sure no one is accessing the VIF before removing */525	mutex_lock(&wil->vif_mutex);526	wil->vifs[mid] = NULL;527	/* ensure NAPI code will see the NULL VIF */528	wmb();529	if (test_bit(wil_status_napi_en, wil->status)) {530		napi_synchronize(&wil->napi_rx);531		napi_synchronize(&wil->napi_tx);532	}533	mutex_unlock(&wil->vif_mutex);534 535	flush_work(&wil->wmi_event_worker);536	del_timer_sync(&vif->connect_timer);537	cancel_work_sync(&vif->disconnect_worker);538	wil_probe_client_flush(vif);539	cancel_work_sync(&vif->probe_client_worker);540	cancel_work_sync(&vif->enable_tx_key_worker);541	/* for VIFs, ndev will be freed by destructor after RTNL is unlocked.542	 * the main interface will be freed in wil_if_free, we need to keep it543	 * a bit longer so logging macros will work.544	 */545}546 547void wil_if_remove(struct wil6210_priv *wil)548{549	struct net_device *ndev = wil->main_ndev;550	struct wireless_dev *wdev = ndev->ieee80211_ptr;551	struct wiphy *wiphy = wdev->wiphy;552 553	wil_dbg_misc(wil, "if_remove\n");554 555	rtnl_lock();556	wiphy_lock(wiphy);557	wil_vif_remove(wil, 0);558	wiphy_unlock(wiphy);559	rtnl_unlock();560 561	netif_napi_del(&wil->napi_tx);562	netif_napi_del(&wil->napi_rx);563 564	free_netdev(wil->napi_ndev);565 566	wiphy_unregister(wiphy);567}568