162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/bitfield.h>
562306a36Sopenharmony_ci#include <linux/netdevice.h>
662306a36Sopenharmony_ci#include <linux/skbuff.h>
762306a36Sopenharmony_ci#include <linux/workqueue.h>
862306a36Sopenharmony_ci#include <net/dst_metadata.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "main.h"
1162306a36Sopenharmony_ci#include "../nfp_net.h"
1262306a36Sopenharmony_ci#include "../nfp_net_repr.h"
1362306a36Sopenharmony_ci#include "./cmsg.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic struct nfp_flower_cmsg_hdr *
1662306a36Sopenharmony_cinfp_flower_cmsg_get_hdr(struct sk_buff *skb)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	return (struct nfp_flower_cmsg_hdr *)skb->data;
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct sk_buff *
2262306a36Sopenharmony_cinfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size,
2362306a36Sopenharmony_ci		      enum nfp_flower_cmsg_type_port type, gfp_t flag)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct nfp_flower_cmsg_hdr *ch;
2662306a36Sopenharmony_ci	struct sk_buff *skb;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	size += NFP_FLOWER_CMSG_HLEN;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	skb = nfp_app_ctrl_msg_alloc(app, size, flag);
3162306a36Sopenharmony_ci	if (!skb)
3262306a36Sopenharmony_ci		return NULL;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	ch = nfp_flower_cmsg_get_hdr(skb);
3562306a36Sopenharmony_ci	ch->pad = 0;
3662306a36Sopenharmony_ci	ch->version = NFP_FLOWER_CMSG_VER1;
3762306a36Sopenharmony_ci	ch->type = type;
3862306a36Sopenharmony_ci	skb_put(skb, size);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return skb;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct sk_buff *
4462306a36Sopenharmony_cinfp_flower_cmsg_mac_repr_start(struct nfp_app *app, unsigned int num_ports)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct nfp_flower_cmsg_mac_repr *msg;
4762306a36Sopenharmony_ci	struct sk_buff *skb;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	skb = nfp_flower_cmsg_alloc(app, struct_size(msg, ports, num_ports),
5062306a36Sopenharmony_ci				    NFP_FLOWER_CMSG_TYPE_MAC_REPR, GFP_KERNEL);
5162306a36Sopenharmony_ci	if (!skb)
5262306a36Sopenharmony_ci		return NULL;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
5562306a36Sopenharmony_ci	memset(msg->reserved, 0, sizeof(msg->reserved));
5662306a36Sopenharmony_ci	msg->num_ports = num_ports;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return skb;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_civoid
6262306a36Sopenharmony_cinfp_flower_cmsg_mac_repr_add(struct sk_buff *skb, unsigned int idx,
6362306a36Sopenharmony_ci			     unsigned int nbi, unsigned int nbi_port,
6462306a36Sopenharmony_ci			     unsigned int phys_port)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct nfp_flower_cmsg_mac_repr *msg;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
6962306a36Sopenharmony_ci	msg->ports[idx].idx = idx;
7062306a36Sopenharmony_ci	msg->ports[idx].info = nbi & NFP_FLOWER_CMSG_MAC_REPR_NBI;
7162306a36Sopenharmony_ci	msg->ports[idx].nbi_port = nbi_port;
7262306a36Sopenharmony_ci	msg->ports[idx].phys_port = phys_port;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciint nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok,
7662306a36Sopenharmony_ci			    unsigned int mtu, bool mtu_only)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct nfp_flower_cmsg_portmod *msg;
7962306a36Sopenharmony_ci	struct sk_buff *skb;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	skb = nfp_flower_cmsg_alloc(repr->app, sizeof(*msg),
8262306a36Sopenharmony_ci				    NFP_FLOWER_CMSG_TYPE_PORT_MOD, GFP_KERNEL);
8362306a36Sopenharmony_ci	if (!skb)
8462306a36Sopenharmony_ci		return -ENOMEM;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
8762306a36Sopenharmony_ci	msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id);
8862306a36Sopenharmony_ci	msg->reserved = 0;
8962306a36Sopenharmony_ci	msg->info = carrier_ok;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (mtu_only)
9262306a36Sopenharmony_ci		msg->info |= NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	msg->mtu = cpu_to_be16(mtu);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	nfp_ctrl_tx(repr->app->ctrl, skb);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return 0;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciint nfp_flower_cmsg_portreify(struct nfp_repr *repr, bool exists)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct nfp_flower_cmsg_portreify *msg;
10462306a36Sopenharmony_ci	struct sk_buff *skb;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	skb = nfp_flower_cmsg_alloc(repr->app, sizeof(*msg),
10762306a36Sopenharmony_ci				    NFP_FLOWER_CMSG_TYPE_PORT_REIFY,
10862306a36Sopenharmony_ci				    GFP_KERNEL);
10962306a36Sopenharmony_ci	if (!skb)
11062306a36Sopenharmony_ci		return -ENOMEM;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
11362306a36Sopenharmony_ci	msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id);
11462306a36Sopenharmony_ci	msg->reserved = 0;
11562306a36Sopenharmony_ci	msg->info = cpu_to_be16(exists);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	nfp_ctrl_tx(repr->app->ctrl, skb);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic bool
12362306a36Sopenharmony_cinfp_flower_process_mtu_ack(struct nfp_app *app, struct sk_buff *skb)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct nfp_flower_priv *app_priv = app->priv;
12662306a36Sopenharmony_ci	struct nfp_flower_cmsg_portmod *msg;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (!(msg->info & NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY))
13162306a36Sopenharmony_ci		return false;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	spin_lock_bh(&app_priv->mtu_conf.lock);
13462306a36Sopenharmony_ci	if (!app_priv->mtu_conf.requested_val ||
13562306a36Sopenharmony_ci	    app_priv->mtu_conf.portnum != be32_to_cpu(msg->portnum) ||
13662306a36Sopenharmony_ci	    be16_to_cpu(msg->mtu) != app_priv->mtu_conf.requested_val) {
13762306a36Sopenharmony_ci		/* Not an ack for requested MTU change. */
13862306a36Sopenharmony_ci		spin_unlock_bh(&app_priv->mtu_conf.lock);
13962306a36Sopenharmony_ci		return false;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	app_priv->mtu_conf.ack = true;
14362306a36Sopenharmony_ci	app_priv->mtu_conf.requested_val = 0;
14462306a36Sopenharmony_ci	wake_up(&app_priv->mtu_conf.wait_q);
14562306a36Sopenharmony_ci	spin_unlock_bh(&app_priv->mtu_conf.lock);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return true;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void
15162306a36Sopenharmony_cinfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct nfp_flower_cmsg_portmod *msg;
15462306a36Sopenharmony_ci	struct net_device *netdev;
15562306a36Sopenharmony_ci	bool link;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
15862306a36Sopenharmony_ci	link = msg->info & NFP_FLOWER_CMSG_PORTMOD_INFO_LINK;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	rtnl_lock();
16162306a36Sopenharmony_ci	rcu_read_lock();
16262306a36Sopenharmony_ci	netdev = nfp_app_dev_get(app, be32_to_cpu(msg->portnum), NULL);
16362306a36Sopenharmony_ci	rcu_read_unlock();
16462306a36Sopenharmony_ci	if (!netdev) {
16562306a36Sopenharmony_ci		nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n",
16662306a36Sopenharmony_ci				     be32_to_cpu(msg->portnum));
16762306a36Sopenharmony_ci		rtnl_unlock();
16862306a36Sopenharmony_ci		return;
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (link) {
17262306a36Sopenharmony_ci		u16 mtu = be16_to_cpu(msg->mtu);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci		netif_carrier_on(netdev);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		/* An MTU of 0 from the firmware should be ignored */
17762306a36Sopenharmony_ci		if (mtu)
17862306a36Sopenharmony_ci			dev_set_mtu(netdev, mtu);
17962306a36Sopenharmony_ci	} else {
18062306a36Sopenharmony_ci		netif_carrier_off(netdev);
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci	rtnl_unlock();
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic void
18662306a36Sopenharmony_cinfp_flower_cmsg_portreify_rx(struct nfp_app *app, struct sk_buff *skb)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct nfp_flower_priv *priv = app->priv;
18962306a36Sopenharmony_ci	struct nfp_flower_cmsg_portreify *msg;
19062306a36Sopenharmony_ci	bool exists;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	rcu_read_lock();
19562306a36Sopenharmony_ci	exists = !!nfp_app_dev_get(app, be32_to_cpu(msg->portnum), NULL);
19662306a36Sopenharmony_ci	rcu_read_unlock();
19762306a36Sopenharmony_ci	if (!exists) {
19862306a36Sopenharmony_ci		nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n",
19962306a36Sopenharmony_ci				     be32_to_cpu(msg->portnum));
20062306a36Sopenharmony_ci		return;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	atomic_inc(&priv->reify_replies);
20462306a36Sopenharmony_ci	wake_up(&priv->reify_wait_queue);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic void
20862306a36Sopenharmony_cinfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb);
21162306a36Sopenharmony_ci	struct nfp_flower_cmsg_merge_hint *msg;
21262306a36Sopenharmony_ci	struct nfp_fl_payload *sub_flows[2];
21362306a36Sopenharmony_ci	struct nfp_flower_priv *priv;
21462306a36Sopenharmony_ci	int err, i, flow_cnt;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
21762306a36Sopenharmony_ci	/* msg->count starts at 0 and always assumes at least 1 entry. */
21862306a36Sopenharmony_ci	flow_cnt = msg->count + 1;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (msg_len < struct_size(msg, flow, flow_cnt)) {
22162306a36Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Merge hint ctrl msg too short - %d bytes but expect %zd\n",
22262306a36Sopenharmony_ci				     msg_len, struct_size(msg, flow, flow_cnt));
22362306a36Sopenharmony_ci		return;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (flow_cnt != 2) {
22762306a36Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Merge hint contains %d flows - two are expected\n",
22862306a36Sopenharmony_ci				     flow_cnt);
22962306a36Sopenharmony_ci		return;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	priv = app->priv;
23362306a36Sopenharmony_ci	mutex_lock(&priv->nfp_fl_lock);
23462306a36Sopenharmony_ci	for (i = 0; i < flow_cnt; i++) {
23562306a36Sopenharmony_ci		u32 ctx = be32_to_cpu(msg->flow[i].host_ctx);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		sub_flows[i] = nfp_flower_get_fl_payload_from_ctx(app, ctx);
23862306a36Sopenharmony_ci		if (!sub_flows[i]) {
23962306a36Sopenharmony_ci			nfp_flower_cmsg_warn(app, "Invalid flow in merge hint\n");
24062306a36Sopenharmony_ci			goto err_mutex_unlock;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	err = nfp_flower_merge_offloaded_flows(app, sub_flows[0], sub_flows[1]);
24562306a36Sopenharmony_ci	/* Only warn on memory fail. Hint veto will not break functionality. */
24662306a36Sopenharmony_ci	if (err == -ENOMEM)
24762306a36Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Flow merge memory fail.\n");
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cierr_mutex_unlock:
25062306a36Sopenharmony_ci	mutex_unlock(&priv->nfp_fl_lock);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic void
25462306a36Sopenharmony_cinfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct nfp_flower_priv *app_priv = app->priv;
25762306a36Sopenharmony_ci	struct nfp_flower_cmsg_hdr *cmsg_hdr;
25862306a36Sopenharmony_ci	enum nfp_flower_cmsg_type_port type;
25962306a36Sopenharmony_ci	bool skb_stored = false;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	cmsg_hdr = nfp_flower_cmsg_get_hdr(skb);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	type = cmsg_hdr->type;
26462306a36Sopenharmony_ci	switch (type) {
26562306a36Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_PORT_MOD:
26662306a36Sopenharmony_ci		nfp_flower_cmsg_portmod_rx(app, skb);
26762306a36Sopenharmony_ci		break;
26862306a36Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_MERGE_HINT:
26962306a36Sopenharmony_ci		if (app_priv->flower_en_feats & NFP_FL_ENABLE_FLOW_MERGE) {
27062306a36Sopenharmony_ci			nfp_flower_cmsg_merge_hint_rx(app, skb);
27162306a36Sopenharmony_ci			break;
27262306a36Sopenharmony_ci		}
27362306a36Sopenharmony_ci		goto err_default;
27462306a36Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_NO_NEIGH:
27562306a36Sopenharmony_ci		nfp_tunnel_request_route_v4(app, skb);
27662306a36Sopenharmony_ci		break;
27762306a36Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_NO_NEIGH_V6:
27862306a36Sopenharmony_ci		nfp_tunnel_request_route_v6(app, skb);
27962306a36Sopenharmony_ci		break;
28062306a36Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_ACTIVE_TUNS:
28162306a36Sopenharmony_ci		nfp_tunnel_keep_alive(app, skb);
28262306a36Sopenharmony_ci		break;
28362306a36Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_ACTIVE_TUNS_V6:
28462306a36Sopenharmony_ci		nfp_tunnel_keep_alive_v6(app, skb);
28562306a36Sopenharmony_ci		break;
28662306a36Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_QOS_STATS:
28762306a36Sopenharmony_ci		nfp_flower_stats_rlim_reply(app, skb);
28862306a36Sopenharmony_ci		break;
28962306a36Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_LAG_CONFIG:
29062306a36Sopenharmony_ci		if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) {
29162306a36Sopenharmony_ci			skb_stored = nfp_flower_lag_unprocessed_msg(app, skb);
29262306a36Sopenharmony_ci			break;
29362306a36Sopenharmony_ci		}
29462306a36Sopenharmony_ci		fallthrough;
29562306a36Sopenharmony_ci	default:
29662306a36Sopenharmony_cierr_default:
29762306a36Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Cannot handle invalid repr control type %u\n",
29862306a36Sopenharmony_ci				     type);
29962306a36Sopenharmony_ci		goto out;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!skb_stored)
30362306a36Sopenharmony_ci		dev_consume_skb_any(skb);
30462306a36Sopenharmony_ci	return;
30562306a36Sopenharmony_ciout:
30662306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_civoid nfp_flower_cmsg_process_rx(struct work_struct *work)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct sk_buff_head cmsg_joined;
31262306a36Sopenharmony_ci	struct nfp_flower_priv *priv;
31362306a36Sopenharmony_ci	struct sk_buff *skb;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	priv = container_of(work, struct nfp_flower_priv, cmsg_work);
31662306a36Sopenharmony_ci	skb_queue_head_init(&cmsg_joined);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	spin_lock_bh(&priv->cmsg_skbs_high.lock);
31962306a36Sopenharmony_ci	skb_queue_splice_tail_init(&priv->cmsg_skbs_high, &cmsg_joined);
32062306a36Sopenharmony_ci	spin_unlock_bh(&priv->cmsg_skbs_high.lock);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	spin_lock_bh(&priv->cmsg_skbs_low.lock);
32362306a36Sopenharmony_ci	skb_queue_splice_tail_init(&priv->cmsg_skbs_low, &cmsg_joined);
32462306a36Sopenharmony_ci	spin_unlock_bh(&priv->cmsg_skbs_low.lock);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&cmsg_joined)))
32762306a36Sopenharmony_ci		nfp_flower_cmsg_process_one_rx(priv->app, skb);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic void
33162306a36Sopenharmony_cinfp_flower_queue_ctl_msg(struct nfp_app *app, struct sk_buff *skb, int type)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct nfp_flower_priv *priv = app->priv;
33462306a36Sopenharmony_ci	struct sk_buff_head *skb_head;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (type == NFP_FLOWER_CMSG_TYPE_PORT_MOD)
33762306a36Sopenharmony_ci		skb_head = &priv->cmsg_skbs_high;
33862306a36Sopenharmony_ci	else
33962306a36Sopenharmony_ci		skb_head = &priv->cmsg_skbs_low;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (skb_queue_len(skb_head) >= NFP_FLOWER_WORKQ_MAX_SKBS) {
34262306a36Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Dropping queued control messages\n");
34362306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
34462306a36Sopenharmony_ci		return;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	skb_queue_tail(skb_head, skb);
34862306a36Sopenharmony_ci	schedule_work(&priv->cmsg_work);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_civoid nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct nfp_flower_cmsg_hdr *cmsg_hdr;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	cmsg_hdr = nfp_flower_cmsg_get_hdr(skb);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (unlikely(cmsg_hdr->version != NFP_FLOWER_CMSG_VER1)) {
35862306a36Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Cannot handle repr control version %u\n",
35962306a36Sopenharmony_ci				     cmsg_hdr->version);
36062306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
36162306a36Sopenharmony_ci		return;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_FLOW_STATS) {
36562306a36Sopenharmony_ci		/* We need to deal with stats updates from HW asap */
36662306a36Sopenharmony_ci		nfp_flower_rx_flow_stats(app, skb);
36762306a36Sopenharmony_ci		dev_consume_skb_any(skb);
36862306a36Sopenharmony_ci	} else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_PORT_MOD &&
36962306a36Sopenharmony_ci		   nfp_flower_process_mtu_ack(app, skb)) {
37062306a36Sopenharmony_ci		/* Handle MTU acks outside wq to prevent RTNL conflict. */
37162306a36Sopenharmony_ci		dev_consume_skb_any(skb);
37262306a36Sopenharmony_ci	} else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH ||
37362306a36Sopenharmony_ci		   cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6) {
37462306a36Sopenharmony_ci		/* Acks from the NFP that the route is added - ignore. */
37562306a36Sopenharmony_ci		dev_consume_skb_any(skb);
37662306a36Sopenharmony_ci	} else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_PORT_REIFY) {
37762306a36Sopenharmony_ci		/* Handle REIFY acks outside wq to prevent RTNL conflict. */
37862306a36Sopenharmony_ci		nfp_flower_cmsg_portreify_rx(app, skb);
37962306a36Sopenharmony_ci		dev_consume_skb_any(skb);
38062306a36Sopenharmony_ci	} else {
38162306a36Sopenharmony_ci		nfp_flower_queue_ctl_msg(app, skb, cmsg_hdr->type);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci}
384