cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lag_conf.c (18505B)


      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_FINISHED
     24};
     25
     26/**
     27 * struct nfp_flower_cmsg_lag_config - control message payload for LAG config
     28 * @ctrl_flags:	Configuration flags
     29 * @reserved:	Reserved for future use
     30 * @ttl:	Time to live of packet - host always sets to 0xff
     31 * @pkt_number:	Config message packet number - increment for each message
     32 * @batch_ver:	Batch version of messages - increment for each batch of messages
     33 * @group_id:	Group ID applicable
     34 * @group_inst:	Group instance number - increment when group is reused
     35 * @members:	Array of 32-bit words listing all active group members
     36 */
     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 group
     50 * @group_id:		Assigned group ID for host/kernel sync
     51 * @group_inst:		Group instance in case of ID reuse
     52 * @list:		List entry
     53 * @master_ndev:	Group master Netdev
     54 * @dirty:		Marked if the group needs synced to HW
     55 * @offloaded:		Marked if the group is currently offloaded to NIC
     56 * @to_remove:		Marked if the group should be removed from NIC
     57 * @to_destroy:		Marked if the group should be removed from driver
     58 * @slave_cnt:		Number of slaves in group
     59 */
     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		0xff
     75
     76/* Use this ID with zero members to ack a batch config */
     77#define NFP_FL_LAG_SYNC_ID		0
     78#define NFP_FL_LAG_GROUP_MIN		1 /* ID 0 reserved */
     79#define NFP_FL_LAG_GROUP_MAX		32 /* 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_simple_get(&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_simple_remove(&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
    157int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
    158				       struct net_device *master,
    159				       struct nfp_fl_pre_lag *pre_act,
    160				       struct netlink_ext_ack *extack)
    161{
    162	struct nfp_flower_priv *priv = app->priv;
    163	struct nfp_fl_lag_group *group = NULL;
    164	__be32 temp_vers;
    165
    166	mutex_lock(&priv->nfp_lag.lock);
    167	group = nfp_fl_lag_find_group_for_master_with_lag(&priv->nfp_lag,
    168							  master);
    169	if (!group) {
    170		mutex_unlock(&priv->nfp_lag.lock);
    171		NL_SET_ERR_MSG_MOD(extack, "invalid entry: group does not exist for LAG action");
    172		return -ENOENT;
    173	}
    174
    175	pre_act->group_id = cpu_to_be16(group->group_id);
    176	temp_vers = cpu_to_be32(priv->nfp_lag.batch_ver <<
    177				NFP_FL_PRE_LAG_VER_OFF);
    178	memcpy(pre_act->lag_version, &temp_vers, 3);
    179	pre_act->instance = group->group_inst;
    180	mutex_unlock(&priv->nfp_lag.lock);
    181
    182	return 0;
    183}
    184
    185int nfp_flower_lag_get_output_id(struct nfp_app *app, struct net_device *master)
    186{
    187	struct nfp_flower_priv *priv = app->priv;
    188	struct nfp_fl_lag_group *group = NULL;
    189	int group_id = -ENOENT;
    190
    191	mutex_lock(&priv->nfp_lag.lock);
    192	group = nfp_fl_lag_find_group_for_master_with_lag(&priv->nfp_lag,
    193							  master);
    194	if (group)
    195		group_id = group->group_id;
    196	mutex_unlock(&priv->nfp_lag.lock);
    197
    198	return group_id;
    199}
    200
    201static int
    202nfp_fl_lag_config_group(struct nfp_fl_lag *lag, struct nfp_fl_lag_group *group,
    203			struct net_device **active_members,
    204			unsigned int member_cnt, enum nfp_fl_lag_batch *batch)
    205{
    206	struct nfp_flower_cmsg_lag_config *cmsg_payload;
    207	struct nfp_flower_priv *priv;
    208	unsigned long int flags;
    209	unsigned int size, i;
    210	struct sk_buff *skb;
    211
    212	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);
    213	size = sizeof(*cmsg_payload) + sizeof(__be32) * member_cnt;
    214	skb = nfp_flower_cmsg_alloc(priv->app, size,
    215				    NFP_FLOWER_CMSG_TYPE_LAG_CONFIG,
    216				    GFP_KERNEL);
    217	if (!skb)
    218		return -ENOMEM;
    219
    220	cmsg_payload = nfp_flower_cmsg_get_data(skb);
    221	flags = 0;
    222
    223	/* Increment batch version for each new batch of config messages. */
    224	if (*batch == NFP_FL_LAG_BATCH_FIRST) {
    225		flags |= NFP_FL_LAG_FIRST;
    226		nfp_fl_increment_version(lag);
    227		*batch = NFP_FL_LAG_BATCH_MEMBER;
    228	}
    229
    230	/* If it is a reset msg then it is also the end of the batch. */
    231	if (lag->rst_cfg) {
    232		flags |= NFP_FL_LAG_RESET;
    233		*batch = NFP_FL_LAG_BATCH_FINISHED;
    234	}
    235
    236	/* To signal the end of a batch, both the switch and last flags are set
    237	 * and the the reserved SYNC group ID is used.
    238	 */
    239	if (*batch == NFP_FL_LAG_BATCH_FINISHED) {
    240		flags |= NFP_FL_LAG_SWITCH | NFP_FL_LAG_LAST;
    241		lag->rst_cfg = false;
    242		cmsg_payload->group_id = cpu_to_be32(NFP_FL_LAG_SYNC_ID);
    243		cmsg_payload->group_inst = 0;
    244	} else {
    245		cmsg_payload->group_id = cpu_to_be32(group->group_id);
    246		cmsg_payload->group_inst = cpu_to_be32(group->group_inst);
    247	}
    248
    249	cmsg_payload->reserved[0] = 0;
    250	cmsg_payload->reserved[1] = 0;
    251	cmsg_payload->ttl = NFP_FL_LAG_HOST_TTL;
    252	cmsg_payload->ctrl_flags = flags;
    253	cmsg_payload->batch_ver = cpu_to_be32(lag->batch_ver);
    254	cmsg_payload->pkt_number = cpu_to_be32(nfp_fl_get_next_pkt_number(lag));
    255
    256	for (i = 0; i < member_cnt; i++)
    257		cmsg_payload->members[i] =
    258			cpu_to_be32(nfp_repr_get_port_id(active_members[i]));
    259
    260	nfp_ctrl_tx(priv->app->ctrl, skb);
    261	return 0;
    262}
    263
    264static void nfp_fl_lag_do_work(struct work_struct *work)
    265{
    266	enum nfp_fl_lag_batch batch = NFP_FL_LAG_BATCH_FIRST;
    267	struct nfp_fl_lag_group *entry, *storage;
    268	struct delayed_work *delayed_work;
    269	struct nfp_flower_priv *priv;
    270	struct nfp_fl_lag *lag;
    271	int err;
    272
    273	delayed_work = to_delayed_work(work);
    274	lag = container_of(delayed_work, struct nfp_fl_lag, work);
    275	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);
    276
    277	mutex_lock(&lag->lock);
    278	list_for_each_entry_safe(entry, storage, &lag->group_list, list) {
    279		struct net_device *iter_netdev, **acti_netdevs;
    280		struct nfp_flower_repr_priv *repr_priv;
    281		int active_count = 0, slaves = 0;
    282		struct nfp_repr *repr;
    283		unsigned long *flags;
    284
    285		if (entry->to_remove) {
    286			/* Active count of 0 deletes group on hw. */
    287			err = nfp_fl_lag_config_group(lag, entry, NULL, 0,
    288						      &batch);
    289			if (!err) {
    290				entry->to_remove = false;
    291				entry->offloaded = false;
    292			} else {
    293				nfp_flower_cmsg_warn(priv->app,
    294						     "group delete failed\n");
    295				schedule_delayed_work(&lag->work,
    296						      NFP_FL_LAG_DELAY);
    297				continue;
    298			}
    299
    300			if (entry->to_destroy) {
    301				ida_simple_remove(&lag->ida_handle,
    302						  entry->group_id);
    303				list_del(&entry->list);
    304				kfree(entry);
    305			}
    306			continue;
    307		}
    308
    309		acti_netdevs = kmalloc_array(entry->slave_cnt,
    310					     sizeof(*acti_netdevs), GFP_KERNEL);
    311
    312		/* Include sanity check in the loop. It may be that a bond has
    313		 * changed between processing the last notification and the
    314		 * work queue triggering. If the number of slaves has changed
    315		 * or it now contains netdevs that cannot be offloaded, ignore
    316		 * the group until pending notifications are processed.
    317		 */
    318		rcu_read_lock();
    319		for_each_netdev_in_bond_rcu(entry->master_ndev, iter_netdev) {
    320			if (!nfp_netdev_is_nfp_repr(iter_netdev)) {
    321				slaves = 0;
    322				break;
    323			}
    324
    325			repr = netdev_priv(iter_netdev);
    326
    327			if (repr->app != priv->app) {
    328				slaves = 0;
    329				break;
    330			}
    331
    332			slaves++;
    333			if (slaves > entry->slave_cnt)
    334				break;
    335
    336			/* Check the ports for state changes. */
    337			repr_priv = repr->app_priv;
    338			flags = &repr_priv->lag_port_flags;
    339
    340			if (*flags & NFP_PORT_LAG_CHANGED) {
    341				*flags &= ~NFP_PORT_LAG_CHANGED;
    342				entry->dirty = true;
    343			}
    344
    345			if ((*flags & NFP_PORT_LAG_TX_ENABLED) &&
    346			    (*flags & NFP_PORT_LAG_LINK_UP))
    347				acti_netdevs[active_count++] = iter_netdev;
    348		}
    349		rcu_read_unlock();
    350
    351		if (slaves != entry->slave_cnt || !entry->dirty) {
    352			kfree(acti_netdevs);
    353			continue;
    354		}
    355
    356		err = nfp_fl_lag_config_group(lag, entry, acti_netdevs,
    357					      active_count, &batch);
    358		if (!err) {
    359			entry->offloaded = true;
    360			entry->dirty = false;
    361		} else {
    362			nfp_flower_cmsg_warn(priv->app,
    363					     "group offload failed\n");
    364			schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);
    365		}
    366
    367		kfree(acti_netdevs);
    368	}
    369
    370	/* End the config batch if at least one packet has been batched. */
    371	if (batch == NFP_FL_LAG_BATCH_MEMBER) {
    372		batch = NFP_FL_LAG_BATCH_FINISHED;
    373		err = nfp_fl_lag_config_group(lag, NULL, NULL, 0, &batch);
    374		if (err)
    375			nfp_flower_cmsg_warn(priv->app,
    376					     "group batch end cmsg failed\n");
    377	}
    378
    379	mutex_unlock(&lag->lock);
    380}
    381
    382static int
    383nfp_fl_lag_put_unprocessed(struct nfp_fl_lag *lag, struct sk_buff *skb)
    384{
    385	struct nfp_flower_cmsg_lag_config *cmsg_payload;
    386
    387	cmsg_payload = nfp_flower_cmsg_get_data(skb);
    388	if (be32_to_cpu(cmsg_payload->group_id) >= NFP_FL_LAG_GROUP_MAX)
    389		return -EINVAL;
    390
    391	/* Drop cmsg retrans if storage limit is exceeded to prevent
    392	 * overloading. If the fw notices that expected messages have not been
    393	 * received in a given time block, it will request a full resync.
    394	 */
    395	if (skb_queue_len(&lag->retrans_skbs) >= NFP_FL_LAG_RETRANS_LIMIT)
    396		return -ENOSPC;
    397
    398	__skb_queue_tail(&lag->retrans_skbs, skb);
    399
    400	return 0;
    401}
    402
    403static void nfp_fl_send_unprocessed(struct nfp_fl_lag *lag)
    404{
    405	struct nfp_flower_priv *priv;
    406	struct sk_buff *skb;
    407
    408	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);
    409
    410	while ((skb = __skb_dequeue(&lag->retrans_skbs)))
    411		nfp_ctrl_tx(priv->app->ctrl, skb);
    412}
    413
    414bool nfp_flower_lag_unprocessed_msg(struct nfp_app *app, struct sk_buff *skb)
    415{
    416	struct nfp_flower_cmsg_lag_config *cmsg_payload;
    417	struct nfp_flower_priv *priv = app->priv;
    418	struct nfp_fl_lag_group *group_entry;
    419	unsigned long int flags;
    420	bool store_skb = false;
    421	int err;
    422
    423	cmsg_payload = nfp_flower_cmsg_get_data(skb);
    424	flags = cmsg_payload->ctrl_flags;
    425
    426	/* Note the intentional fall through below. If DATA and XON are both
    427	 * set, the message will stored and sent again with the rest of the
    428	 * unprocessed messages list.
    429	 */
    430
    431	/* Store */
    432	if (flags & NFP_FL_LAG_DATA)
    433		if (!nfp_fl_lag_put_unprocessed(&priv->nfp_lag, skb))
    434			store_skb = true;
    435
    436	/* Send stored */
    437	if (flags & NFP_FL_LAG_XON)
    438		nfp_fl_send_unprocessed(&priv->nfp_lag);
    439
    440	/* Resend all */
    441	if (flags & NFP_FL_LAG_SYNC) {
    442		/* To resend all config:
    443		 * 1) Clear all unprocessed messages
    444		 * 2) Mark all groups dirty
    445		 * 3) Reset NFP group config
    446		 * 4) Schedule a LAG config update
    447		 */
    448
    449		__skb_queue_purge(&priv->nfp_lag.retrans_skbs);
    450
    451		mutex_lock(&priv->nfp_lag.lock);
    452		list_for_each_entry(group_entry, &priv->nfp_lag.group_list,
    453				    list)
    454			group_entry->dirty = true;
    455
    456		err = nfp_flower_lag_reset(&priv->nfp_lag);
    457		if (err)
    458			nfp_flower_cmsg_warn(priv->app,
    459					     "mem err in group reset msg\n");
    460		mutex_unlock(&priv->nfp_lag.lock);
    461
    462		schedule_delayed_work(&priv->nfp_lag.work, 0);
    463	}
    464
    465	return store_skb;
    466}
    467
    468static void
    469nfp_fl_lag_schedule_group_remove(struct nfp_fl_lag *lag,
    470				 struct nfp_fl_lag_group *group)
    471{
    472	group->to_remove = true;
    473
    474	schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);
    475}
    476
    477static void
    478nfp_fl_lag_schedule_group_delete(struct nfp_fl_lag *lag,
    479				 struct net_device *master)
    480{
    481	struct nfp_fl_lag_group *group;
    482	struct nfp_flower_priv *priv;
    483
    484	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);
    485
    486	if (!netif_is_bond_master(master))
    487		return;
    488
    489	mutex_lock(&lag->lock);
    490	group = nfp_fl_lag_find_group_for_master_with_lag(lag, master);
    491	if (!group) {
    492		mutex_unlock(&lag->lock);
    493		nfp_warn(priv->app->cpp, "untracked bond got unregistered %s\n",
    494			 netdev_name(master));
    495		return;
    496	}
    497
    498	group->to_remove = true;
    499	group->to_destroy = true;
    500	mutex_unlock(&lag->lock);
    501
    502	schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);
    503}
    504
    505static int
    506nfp_fl_lag_changeupper_event(struct nfp_fl_lag *lag,
    507			     struct netdev_notifier_changeupper_info *info)
    508{
    509	struct net_device *upper = info->upper_dev, *iter_netdev;
    510	struct netdev_lag_upper_info *lag_upper_info;
    511	struct nfp_fl_lag_group *group;
    512	struct nfp_flower_priv *priv;
    513	unsigned int slave_count = 0;
    514	bool can_offload = true;
    515	struct nfp_repr *repr;
    516
    517	if (!netif_is_lag_master(upper))
    518		return 0;
    519
    520	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);
    521
    522	rcu_read_lock();
    523	for_each_netdev_in_bond_rcu(upper, iter_netdev) {
    524		if (!nfp_netdev_is_nfp_repr(iter_netdev)) {
    525			can_offload = false;
    526			break;
    527		}
    528		repr = netdev_priv(iter_netdev);
    529
    530		/* Ensure all ports are created by the same app/on same card. */
    531		if (repr->app != priv->app) {
    532			can_offload = false;
    533			break;
    534		}
    535
    536		slave_count++;
    537	}
    538	rcu_read_unlock();
    539
    540	lag_upper_info = info->upper_info;
    541
    542	/* Firmware supports active/backup and L3/L4 hash bonds. */
    543	if (lag_upper_info &&
    544	    lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_ACTIVEBACKUP &&
    545	    (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH ||
    546	     (lag_upper_info->hash_type != NETDEV_LAG_HASH_L34 &&
    547	      lag_upper_info->hash_type != NETDEV_LAG_HASH_E34 &&
    548	      lag_upper_info->hash_type != NETDEV_LAG_HASH_UNKNOWN))) {
    549		can_offload = false;
    550		nfp_flower_cmsg_warn(priv->app,
    551				     "Unable to offload tx_type %u hash %u\n",
    552				     lag_upper_info->tx_type,
    553				     lag_upper_info->hash_type);
    554	}
    555
    556	mutex_lock(&lag->lock);
    557	group = nfp_fl_lag_find_group_for_master_with_lag(lag, upper);
    558
    559	if (slave_count == 0 || !can_offload) {
    560		/* Cannot offload the group - remove if previously offloaded. */
    561		if (group && group->offloaded)
    562			nfp_fl_lag_schedule_group_remove(lag, group);
    563
    564		mutex_unlock(&lag->lock);
    565		return 0;
    566	}
    567
    568	if (!group) {
    569		group = nfp_fl_lag_group_create(lag, upper);
    570		if (IS_ERR(group)) {
    571			mutex_unlock(&lag->lock);
    572			return PTR_ERR(group);
    573		}
    574	}
    575
    576	group->dirty = true;
    577	group->slave_cnt = slave_count;
    578
    579	/* Group may have been on queue for removal but is now offloable. */
    580	group->to_remove = false;
    581	mutex_unlock(&lag->lock);
    582
    583	schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);
    584	return 0;
    585}
    586
    587static void
    588nfp_fl_lag_changels_event(struct nfp_fl_lag *lag, struct net_device *netdev,
    589			  struct netdev_notifier_changelowerstate_info *info)
    590{
    591	struct netdev_lag_lower_state_info *lag_lower_info;
    592	struct nfp_flower_repr_priv *repr_priv;
    593	struct nfp_flower_priv *priv;
    594	struct nfp_repr *repr;
    595	unsigned long *flags;
    596
    597	if (!netif_is_lag_port(netdev) || !nfp_netdev_is_nfp_repr(netdev))
    598		return;
    599
    600	lag_lower_info = info->lower_state_info;
    601	if (!lag_lower_info)
    602		return;
    603
    604	priv = container_of(lag, struct nfp_flower_priv, nfp_lag);
    605	repr = netdev_priv(netdev);
    606
    607	/* Verify that the repr is associated with this app. */
    608	if (repr->app != priv->app)
    609		return;
    610
    611	repr_priv = repr->app_priv;
    612	flags = &repr_priv->lag_port_flags;
    613
    614	mutex_lock(&lag->lock);
    615	if (lag_lower_info->link_up)
    616		*flags |= NFP_PORT_LAG_LINK_UP;
    617	else
    618		*flags &= ~NFP_PORT_LAG_LINK_UP;
    619
    620	if (lag_lower_info->tx_enabled)
    621		*flags |= NFP_PORT_LAG_TX_ENABLED;
    622	else
    623		*flags &= ~NFP_PORT_LAG_TX_ENABLED;
    624
    625	*flags |= NFP_PORT_LAG_CHANGED;
    626	mutex_unlock(&lag->lock);
    627
    628	schedule_delayed_work(&lag->work, NFP_FL_LAG_DELAY);
    629}
    630
    631int nfp_flower_lag_netdev_event(struct nfp_flower_priv *priv,
    632				struct net_device *netdev,
    633				unsigned long event, void *ptr)
    634{
    635	struct nfp_fl_lag *lag = &priv->nfp_lag;
    636	int err;
    637
    638	switch (event) {
    639	case NETDEV_CHANGEUPPER:
    640		err = nfp_fl_lag_changeupper_event(lag, ptr);
    641		if (err)
    642			return NOTIFY_BAD;
    643		return NOTIFY_OK;
    644	case NETDEV_CHANGELOWERSTATE:
    645		nfp_fl_lag_changels_event(lag, netdev, ptr);
    646		return NOTIFY_OK;
    647	case NETDEV_UNREGISTER:
    648		nfp_fl_lag_schedule_group_delete(lag, netdev);
    649		return NOTIFY_OK;
    650	}
    651
    652	return NOTIFY_DONE;
    653}
    654
    655int nfp_flower_lag_reset(struct nfp_fl_lag *lag)
    656{
    657	enum nfp_fl_lag_batch batch = NFP_FL_LAG_BATCH_FIRST;
    658
    659	lag->rst_cfg = true;
    660	return nfp_fl_lag_config_group(lag, NULL, NULL, 0, &batch);
    661}
    662
    663void nfp_flower_lag_init(struct nfp_fl_lag *lag)
    664{
    665	INIT_DELAYED_WORK(&lag->work, nfp_fl_lag_do_work);
    666	INIT_LIST_HEAD(&lag->group_list);
    667	mutex_init(&lag->lock);
    668	ida_init(&lag->ida_handle);
    669
    670	__skb_queue_head_init(&lag->retrans_skbs);
    671
    672	/* 0 is a reserved batch version so increment to first valid value. */
    673	nfp_fl_increment_version(lag);
    674}
    675
    676void nfp_flower_lag_cleanup(struct nfp_fl_lag *lag)
    677{
    678	struct nfp_fl_lag_group *entry, *storage;
    679
    680	cancel_delayed_work_sync(&lag->work);
    681
    682	__skb_queue_purge(&lag->retrans_skbs);
    683
    684	/* Remove all groups. */
    685	mutex_lock(&lag->lock);
    686	list_for_each_entry_safe(entry, storage, &lag->group_list, list) {
    687		list_del(&entry->list);
    688		kfree(entry);
    689	}
    690	mutex_unlock(&lag->lock);
    691	mutex_destroy(&lag->lock);
    692	ida_destroy(&lag->ida_handle);
    693}