brintos

brintos / linux-shallow public Read only

0
0
Text · 18.7 KiB · 2c7bd6e Raw
728 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2018 Netronome Systems, Inc. */3 4#include "main.h"5 6/* LAG group config flags. */7#define NFP_FL_LAG_LAST			BIT(1)8#define NFP_FL_LAG_FIRST		BIT(2)9#define NFP_FL_LAG_DATA			BIT(3)10#define NFP_FL_LAG_XON			BIT(4)11#define NFP_FL_LAG_SYNC			BIT(5)12#define NFP_FL_LAG_SWITCH		BIT(6)13#define NFP_FL_LAG_RESET		BIT(7)14 15/* LAG port state flags. */16#define NFP_PORT_LAG_LINK_UP		BIT(0)17#define NFP_PORT_LAG_TX_ENABLED		BIT(1)18#define NFP_PORT_LAG_CHANGED		BIT(2)19 20enum nfp_fl_lag_batch {21	NFP_FL_LAG_BATCH_FIRST,22	NFP_FL_LAG_BATCH_MEMBER,23	NFP_FL_LAG_BATCH_FINISHED24};25 26/**27 * struct nfp_flower_cmsg_lag_config - control message payload for LAG config28 * @ctrl_flags:	Configuration flags29 * @reserved:	Reserved for future use30 * @ttl:	Time to live of packet - host always sets to 0xff31 * @pkt_number:	Config message packet number - increment for each message32 * @batch_ver:	Batch version of messages - increment for each batch of messages33 * @group_id:	Group ID applicable34 * @group_inst:	Group instance number - increment when group is reused35 * @members:	Array of 32-bit words listing all active group members36 */37struct nfp_flower_cmsg_lag_config {38	u8 ctrl_flags;39	u8 reserved[2];40	u8 ttl;41	__be32 pkt_number;42	__be32 batch_ver;43	__be32 group_id;44	__be32 group_inst;45	__be32 members[];46};47 48/**49 * struct nfp_fl_lag_group - list entry for each LAG group50 * @group_id:		Assigned group ID for host/kernel sync51 * @group_inst:		Group instance in case of ID reuse52 * @list:		List entry53 * @master_ndev:	Group master Netdev54 * @dirty:		Marked if the group needs synced to HW55 * @offloaded:		Marked if the group is currently offloaded to NIC56 * @to_remove:		Marked if the group should be removed from NIC57 * @to_destroy:		Marked if the group should be removed from driver58 * @slave_cnt:		Number of slaves in group59 */60struct nfp_fl_lag_group {61	unsigned int group_id;62	u8 group_inst;63	struct list_head list;64	struct net_device *master_ndev;65	bool dirty;66	bool offloaded;67	bool to_remove;68	bool to_destroy;69	unsigned int slave_cnt;70};71 72#define NFP_FL_LAG_PKT_NUMBER_MASK	GENMASK(30, 0)73#define NFP_FL_LAG_VERSION_MASK		GENMASK(22, 0)74#define NFP_FL_LAG_HOST_TTL		0xff75 76/* Use this ID with zero members to ack a batch config */77#define NFP_FL_LAG_SYNC_ID		078#define NFP_FL_LAG_GROUP_MIN		1 /* ID 0 reserved */79#define NFP_FL_LAG_GROUP_MAX		31 /* IDs 1 to 31 are valid */80 81/* wait for more config */82#define NFP_FL_LAG_DELAY		(msecs_to_jiffies(2))83 84#define NFP_FL_LAG_RETRANS_LIMIT	100 /* max retrans cmsgs to store */85 86static unsigned int nfp_fl_get_next_pkt_number(struct nfp_fl_lag *lag)87{88	lag->pkt_num++;89	lag->pkt_num &= NFP_FL_LAG_PKT_NUMBER_MASK;90 91	return lag->pkt_num;92}93 94static void nfp_fl_increment_version(struct nfp_fl_lag *lag)95{96	/* LSB is not considered by firmware so add 2 for each increment. */97	lag->batch_ver += 2;98	lag->batch_ver &= NFP_FL_LAG_VERSION_MASK;99 100	/* Zero is reserved by firmware. */101	if (!lag->batch_ver)102		lag->batch_ver += 2;103}104 105static struct nfp_fl_lag_group *106nfp_fl_lag_group_create(struct nfp_fl_lag *lag, struct net_device *master)107{108	struct nfp_fl_lag_group *group;109	struct nfp_flower_priv *priv;110	int id;111 112	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);113 114	id = ida_alloc_range(&lag->ida_handle, NFP_FL_LAG_GROUP_MIN,115			     NFP_FL_LAG_GROUP_MAX, GFP_KERNEL);116	if (id < 0) {117		nfp_flower_cmsg_warn(priv->app,118				     "No more bonding groups available\n");119		return ERR_PTR(id);120	}121 122	group = kmalloc(sizeof(*group), GFP_KERNEL);123	if (!group) {124		ida_free(&lag->ida_handle, id);125		return ERR_PTR(-ENOMEM);126	}127 128	group->group_id = id;129	group->master_ndev = master;130	group->dirty = true;131	group->offloaded = false;132	group->to_remove = false;133	group->to_destroy = false;134	group->slave_cnt = 0;135	group->group_inst = ++lag->global_inst;136	list_add_tail(&group->list, &lag->group_list);137 138	return group;139}140 141static struct nfp_fl_lag_group *142nfp_fl_lag_find_group_for_master_with_lag(struct nfp_fl_lag *lag,143					  struct net_device *master)144{145	struct nfp_fl_lag_group *entry;146 147	if (!master)148		return NULL;149 150	list_for_each_entry(entry, &lag->group_list, list)151		if (entry->master_ndev == master)152			return entry;153 154	return NULL;155}156 157static int nfp_fl_lag_get_group_info(struct nfp_app *app,158				     struct net_device *netdev,159				     __be16 *group_id,160				     u8 *batch_ver,161				     u8 *group_inst)162{163	struct nfp_flower_priv *priv = app->priv;164	struct nfp_fl_lag_group *group = NULL;165	__be32 temp_vers;166 167	mutex_lock(&priv->nfp_lag.lock);168	group = nfp_fl_lag_find_group_for_master_with_lag(&priv->nfp_lag,169							  netdev);170	if (!group) {171		mutex_unlock(&priv->nfp_lag.lock);172		return -ENOENT;173	}174 175	if (group_id)176		*group_id = cpu_to_be16(group->group_id);177 178	if (batch_ver) {179		temp_vers = cpu_to_be32(priv->nfp_lag.batch_ver <<180					NFP_FL_PRE_LAG_VER_OFF);181		memcpy(batch_ver, &temp_vers, 3);182	}183 184	if (group_inst)185		*group_inst = group->group_inst;186 187	mutex_unlock(&priv->nfp_lag.lock);188 189	return 0;190}191 192int nfp_flower_lag_populate_pre_action(struct nfp_app *app,193				       struct net_device *master,194				       struct nfp_fl_pre_lag *pre_act,195				       struct netlink_ext_ack *extack)196{197	if (nfp_fl_lag_get_group_info(app, master, &pre_act->group_id,198				      pre_act->lag_version,199				      &pre_act->instance)) {200		NL_SET_ERR_MSG_MOD(extack, "invalid entry: group does not exist for LAG action");201		return -ENOENT;202	}203 204	return 0;205}206 207void nfp_flower_lag_get_info_from_netdev(struct nfp_app *app,208					 struct net_device *netdev,209					 struct nfp_tun_neigh_lag *lag)210{211	nfp_fl_lag_get_group_info(app, netdev, NULL,212				  lag->lag_version, &lag->lag_instance);213}214 215int nfp_flower_lag_get_output_id(struct nfp_app *app, struct net_device *master)216{217	struct nfp_flower_priv *priv = app->priv;218	struct nfp_fl_lag_group *group = NULL;219	int group_id = -ENOENT;220 221	mutex_lock(&priv->nfp_lag.lock);222	group = nfp_fl_lag_find_group_for_master_with_lag(&priv->nfp_lag,223							  master);224	if (group)225		group_id = group->group_id;226	mutex_unlock(&priv->nfp_lag.lock);227 228	return group_id;229}230 231static int232nfp_fl_lag_config_group(struct nfp_fl_lag *lag, struct nfp_fl_lag_group *group,233			struct net_device **active_members,234			unsigned int member_cnt, enum nfp_fl_lag_batch *batch)235{236	struct nfp_flower_cmsg_lag_config *cmsg_payload;237	struct nfp_flower_priv *priv;238	unsigned long int flags;239	unsigned int size, i;240	struct sk_buff *skb;241 242	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);243	size = sizeof(*cmsg_payload) + sizeof(__be32) * member_cnt;244	skb = nfp_flower_cmsg_alloc(priv->app, size,245				    NFP_FLOWER_CMSG_TYPE_LAG_CONFIG,246				    GFP_KERNEL);247	if (!skb)248		return -ENOMEM;249 250	cmsg_payload = nfp_flower_cmsg_get_data(skb);251	flags = 0;252 253	/* Increment batch version for each new batch of config messages. */254	if (*batch == NFP_FL_LAG_BATCH_FIRST) {255		flags |= NFP_FL_LAG_FIRST;256		nfp_fl_increment_version(lag);257		*batch = NFP_FL_LAG_BATCH_MEMBER;258	}259 260	/* If it is a reset msg then it is also the end of the batch. */261	if (lag->rst_cfg) {262		flags |= NFP_FL_LAG_RESET;263		*batch = NFP_FL_LAG_BATCH_FINISHED;264	}265 266	/* To signal the end of a batch, both the switch and last flags are set267	 * and the reserved SYNC group ID is used.268	 */269	if (*batch == NFP_FL_LAG_BATCH_FINISHED) {270		flags |= NFP_FL_LAG_SWITCH | NFP_FL_LAG_LAST;271		lag->rst_cfg = false;272		cmsg_payload->group_id = cpu_to_be32(NFP_FL_LAG_SYNC_ID);273		cmsg_payload->group_inst = 0;274	} else {275		cmsg_payload->group_id = cpu_to_be32(group->group_id);276		cmsg_payload->group_inst = cpu_to_be32(group->group_inst);277	}278 279	cmsg_payload->reserved[0] = 0;280	cmsg_payload->reserved[1] = 0;281	cmsg_payload->ttl = NFP_FL_LAG_HOST_TTL;282	cmsg_payload->ctrl_flags = flags;283	cmsg_payload->batch_ver = cpu_to_be32(lag->batch_ver);284	cmsg_payload->pkt_number = cpu_to_be32(nfp_fl_get_next_pkt_number(lag));285 286	for (i = 0; i < member_cnt; i++)287		cmsg_payload->members[i] =288			cpu_to_be32(nfp_repr_get_port_id(active_members[i]));289 290	nfp_ctrl_tx(priv->app->ctrl, skb);291	return 0;292}293 294static void nfp_fl_lag_do_work(struct work_struct *work)295{296	enum nfp_fl_lag_batch batch = NFP_FL_LAG_BATCH_FIRST;297	struct nfp_fl_lag_group *entry, *storage;298	struct delayed_work *delayed_work;299	struct nfp_flower_priv *priv;300	struct nfp_fl_lag *lag;301	int err;302 303	delayed_work = to_delayed_work(work);304	lag = container_of(delayed_work, struct nfp_fl_lag, work);305	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);306 307	mutex_lock(&lag->lock);308	list_for_each_entry_safe(entry, storage, &lag->group_list, list) {309		struct net_device *iter_netdev, **acti_netdevs;310		struct nfp_flower_repr_priv *repr_priv;311		int active_count = 0, slaves = 0;312		struct nfp_repr *repr;313		unsigned long *flags;314 315		if (entry->to_remove) {316			/* Active count of 0 deletes group on hw. */317			err = nfp_fl_lag_config_group(lag, entry, NULL, 0,318						      &batch);319			if (!err) {320				entry->to_remove = false;321				entry->offloaded = false;322			} else {323				nfp_flower_cmsg_warn(priv->app,324						     "group delete failed\n");325				schedule_delayed_work(&lag->work,326						      NFP_FL_LAG_DELAY);327				continue;328			}329 330			if (entry->to_destroy) {331				ida_free(&lag->ida_handle, entry->group_id);332				list_del(&entry->list);333				kfree(entry);334			}335			continue;336		}337 338		acti_netdevs = kmalloc_array(entry->slave_cnt,339					     sizeof(*acti_netdevs), GFP_KERNEL);340		if (!acti_netdevs) {341			schedule_delayed_work(&lag->work,342					      NFP_FL_LAG_DELAY);343			continue;344		}345 346		/* Include sanity check in the loop. It may be that a bond has347		 * changed between processing the last notification and the348		 * work queue triggering. If the number of slaves has changed349		 * or it now contains netdevs that cannot be offloaded, ignore350		 * the group until pending notifications are processed.351		 */352		rcu_read_lock();353		for_each_netdev_in_bond_rcu(entry->master_ndev, iter_netdev) {354			if (!nfp_netdev_is_nfp_repr(iter_netdev)) {355				slaves = 0;356				break;357			}358 359			repr = netdev_priv(iter_netdev);360 361			if (repr->app != priv->app) {362				slaves = 0;363				break;364			}365 366			slaves++;367			if (slaves > entry->slave_cnt)368				break;369 370			/* Check the ports for state changes. */371			repr_priv = repr->app_priv;372			flags = &repr_priv->lag_port_flags;373 374			if (*flags & NFP_PORT_LAG_CHANGED) {375				*flags &= ~NFP_PORT_LAG_CHANGED;376				entry->dirty = true;377			}378 379			if ((*flags & NFP_PORT_LAG_TX_ENABLED) &&380			    (*flags & NFP_PORT_LAG_LINK_UP))381				acti_netdevs[active_count++] = iter_netdev;382		}383		rcu_read_unlock();384 385		if (slaves != entry->slave_cnt || !entry->dirty) {386			kfree(acti_netdevs);387			continue;388		}389 390		err = nfp_fl_lag_config_group(lag, entry, acti_netdevs,391					      active_count, &batch);392		if (!err) {393			entry->offloaded = true;394			entry->dirty = false;395		} else {396			nfp_flower_cmsg_warn(priv->app,397					     "group offload failed\n");398			schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);399		}400 401		kfree(acti_netdevs);402	}403 404	/* End the config batch if at least one packet has been batched. */405	if (batch == NFP_FL_LAG_BATCH_MEMBER) {406		batch = NFP_FL_LAG_BATCH_FINISHED;407		err = nfp_fl_lag_config_group(lag, NULL, NULL, 0, &batch);408		if (err)409			nfp_flower_cmsg_warn(priv->app,410					     "group batch end cmsg failed\n");411	}412 413	mutex_unlock(&lag->lock);414}415 416static int417nfp_fl_lag_put_unprocessed(struct nfp_fl_lag *lag, struct sk_buff *skb)418{419	struct nfp_flower_cmsg_lag_config *cmsg_payload;420 421	cmsg_payload = nfp_flower_cmsg_get_data(skb);422	if (be32_to_cpu(cmsg_payload->group_id) > NFP_FL_LAG_GROUP_MAX)423		return -EINVAL;424 425	/* Drop cmsg retrans if storage limit is exceeded to prevent426	 * overloading. If the fw notices that expected messages have not been427	 * received in a given time block, it will request a full resync.428	 */429	if (skb_queue_len(&lag->retrans_skbs) >= NFP_FL_LAG_RETRANS_LIMIT)430		return -ENOSPC;431 432	__skb_queue_tail(&lag->retrans_skbs, skb);433 434	return 0;435}436 437static void nfp_fl_send_unprocessed(struct nfp_fl_lag *lag)438{439	struct nfp_flower_priv *priv;440	struct sk_buff *skb;441 442	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);443 444	while ((skb = __skb_dequeue(&lag->retrans_skbs)))445		nfp_ctrl_tx(priv->app->ctrl, skb);446}447 448bool nfp_flower_lag_unprocessed_msg(struct nfp_app *app, struct sk_buff *skb)449{450	struct nfp_flower_cmsg_lag_config *cmsg_payload;451	struct nfp_flower_priv *priv = app->priv;452	struct nfp_fl_lag_group *group_entry;453	unsigned long int flags;454	bool store_skb = false;455	int err;456 457	cmsg_payload = nfp_flower_cmsg_get_data(skb);458	flags = cmsg_payload->ctrl_flags;459 460	/* Note the intentional fall through below. If DATA and XON are both461	 * set, the message will stored and sent again with the rest of the462	 * unprocessed messages list.463	 */464 465	/* Store */466	if (flags & NFP_FL_LAG_DATA)467		if (!nfp_fl_lag_put_unprocessed(&priv->nfp_lag, skb))468			store_skb = true;469 470	/* Send stored */471	if (flags & NFP_FL_LAG_XON)472		nfp_fl_send_unprocessed(&priv->nfp_lag);473 474	/* Resend all */475	if (flags & NFP_FL_LAG_SYNC) {476		/* To resend all config:477		 * 1) Clear all unprocessed messages478		 * 2) Mark all groups dirty479		 * 3) Reset NFP group config480		 * 4) Schedule a LAG config update481		 */482 483		__skb_queue_purge(&priv->nfp_lag.retrans_skbs);484 485		mutex_lock(&priv->nfp_lag.lock);486		list_for_each_entry(group_entry, &priv->nfp_lag.group_list,487				    list)488			group_entry->dirty = true;489 490		err = nfp_flower_lag_reset(&priv->nfp_lag);491		if (err)492			nfp_flower_cmsg_warn(priv->app,493					     "mem err in group reset msg\n");494		mutex_unlock(&priv->nfp_lag.lock);495 496		schedule_delayed_work(&priv->nfp_lag.work, 0);497	}498 499	return store_skb;500}501 502static void503nfp_fl_lag_schedule_group_remove(struct nfp_fl_lag *lag,504				 struct nfp_fl_lag_group *group)505{506	group->to_remove = true;507 508	schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);509}510 511static void512nfp_fl_lag_schedule_group_delete(struct nfp_fl_lag *lag,513				 struct net_device *master)514{515	struct nfp_fl_lag_group *group;516	struct nfp_flower_priv *priv;517 518	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);519 520	if (!netif_is_bond_master(master))521		return;522 523	mutex_lock(&lag->lock);524	group = nfp_fl_lag_find_group_for_master_with_lag(lag, master);525	if (!group) {526		mutex_unlock(&lag->lock);527		nfp_warn(priv->app->cpp, "untracked bond got unregistered %s\n",528			 netdev_name(master));529		return;530	}531 532	group->to_remove = true;533	group->to_destroy = true;534	mutex_unlock(&lag->lock);535 536	schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);537}538 539static int540nfp_fl_lag_changeupper_event(struct nfp_fl_lag *lag,541			     struct netdev_notifier_changeupper_info *info)542{543	struct net_device *upper = info->upper_dev, *iter_netdev;544	struct netdev_lag_upper_info *lag_upper_info;545	struct nfp_fl_lag_group *group;546	struct nfp_flower_priv *priv;547	unsigned int slave_count = 0;548	bool can_offload = true;549	struct nfp_repr *repr;550 551	if (!netif_is_lag_master(upper))552		return 0;553 554	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);555 556	rcu_read_lock();557	for_each_netdev_in_bond_rcu(upper, iter_netdev) {558		if (!nfp_netdev_is_nfp_repr(iter_netdev)) {559			can_offload = false;560			break;561		}562		repr = netdev_priv(iter_netdev);563 564		/* Ensure all ports are created by the same app/on same card. */565		if (repr->app != priv->app) {566			can_offload = false;567			break;568		}569 570		slave_count++;571	}572	rcu_read_unlock();573 574	lag_upper_info = info->upper_info;575 576	/* Firmware supports active/backup and L3/L4 hash bonds. */577	if (lag_upper_info &&578	    lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_ACTIVEBACKUP &&579	    (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH ||580	     (lag_upper_info->hash_type != NETDEV_LAG_HASH_L34 &&581	      lag_upper_info->hash_type != NETDEV_LAG_HASH_E34 &&582	      lag_upper_info->hash_type != NETDEV_LAG_HASH_UNKNOWN))) {583		can_offload = false;584		nfp_flower_cmsg_warn(priv->app,585				     "Unable to offload tx_type %u hash %u\n",586				     lag_upper_info->tx_type,587				     lag_upper_info->hash_type);588	}589 590	mutex_lock(&lag->lock);591	group = nfp_fl_lag_find_group_for_master_with_lag(lag, upper);592 593	if (slave_count == 0 || !can_offload) {594		/* Cannot offload the group - remove if previously offloaded. */595		if (group && group->offloaded)596			nfp_fl_lag_schedule_group_remove(lag, group);597 598		mutex_unlock(&lag->lock);599		return 0;600	}601 602	if (!group) {603		group = nfp_fl_lag_group_create(lag, upper);604		if (IS_ERR(group)) {605			mutex_unlock(&lag->lock);606			return PTR_ERR(group);607		}608	}609 610	group->dirty = true;611	group->slave_cnt = slave_count;612 613	/* Group may have been on queue for removal but is now offloadable. */614	group->to_remove = false;615	mutex_unlock(&lag->lock);616 617	schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);618	return 0;619}620 621static void622nfp_fl_lag_changels_event(struct nfp_fl_lag *lag, struct net_device *netdev,623			  struct netdev_notifier_changelowerstate_info *info)624{625	struct netdev_lag_lower_state_info *lag_lower_info;626	struct nfp_flower_repr_priv *repr_priv;627	struct nfp_flower_priv *priv;628	struct nfp_repr *repr;629	unsigned long *flags;630 631	if (!netif_is_lag_port(netdev) || !nfp_netdev_is_nfp_repr(netdev))632		return;633 634	lag_lower_info = info->lower_state_info;635	if (!lag_lower_info)636		return;637 638	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);639	repr = netdev_priv(netdev);640 641	/* Verify that the repr is associated with this app. */642	if (repr->app != priv->app)643		return;644 645	repr_priv = repr->app_priv;646	flags = &repr_priv->lag_port_flags;647 648	mutex_lock(&lag->lock);649	if (lag_lower_info->link_up)650		*flags |= NFP_PORT_LAG_LINK_UP;651	else652		*flags &= ~NFP_PORT_LAG_LINK_UP;653 654	if (lag_lower_info->tx_enabled)655		*flags |= NFP_PORT_LAG_TX_ENABLED;656	else657		*flags &= ~NFP_PORT_LAG_TX_ENABLED;658 659	*flags |= NFP_PORT_LAG_CHANGED;660	mutex_unlock(&lag->lock);661 662	schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);663}664 665int nfp_flower_lag_netdev_event(struct nfp_flower_priv *priv,666				struct net_device *netdev,667				unsigned long event, void *ptr)668{669	struct nfp_fl_lag *lag = &priv->nfp_lag;670	int err;671 672	switch (event) {673	case NETDEV_CHANGEUPPER:674		err = nfp_fl_lag_changeupper_event(lag, ptr);675		if (err)676			return NOTIFY_BAD;677		return NOTIFY_OK;678	case NETDEV_CHANGELOWERSTATE:679		nfp_fl_lag_changels_event(lag, netdev, ptr);680		return NOTIFY_OK;681	case NETDEV_UNREGISTER:682		nfp_fl_lag_schedule_group_delete(lag, netdev);683		return NOTIFY_OK;684	}685 686	return NOTIFY_DONE;687}688 689int nfp_flower_lag_reset(struct nfp_fl_lag *lag)690{691	enum nfp_fl_lag_batch batch = NFP_FL_LAG_BATCH_FIRST;692 693	lag->rst_cfg = true;694	return nfp_fl_lag_config_group(lag, NULL, NULL, 0, &batch);695}696 697void nfp_flower_lag_init(struct nfp_fl_lag *lag)698{699	INIT_DELAYED_WORK(&lag->work, nfp_fl_lag_do_work);700	INIT_LIST_HEAD(&lag->group_list);701	mutex_init(&lag->lock);702	ida_init(&lag->ida_handle);703 704	__skb_queue_head_init(&lag->retrans_skbs);705 706	/* 0 is a reserved batch version so increment to first valid value. */707	nfp_fl_increment_version(lag);708}709 710void nfp_flower_lag_cleanup(struct nfp_fl_lag *lag)711{712	struct nfp_fl_lag_group *entry, *storage;713 714	cancel_delayed_work_sync(&lag->work);715 716	__skb_queue_purge(&lag->retrans_skbs);717 718	/* Remove all groups. */719	mutex_lock(&lag->lock);720	list_for_each_entry_safe(entry, storage, &lag->group_list, list) {721		list_del(&entry->list);722		kfree(entry);723	}724	mutex_unlock(&lag->lock);725	mutex_destroy(&lag->lock);726	ida_destroy(&lag->ida_handle);727}728