18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
28c2ecf20Sopenharmony_ci/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
58c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
68c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
78c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
88c2ecf20Sopenharmony_ci#include <net/dst_metadata.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "main.h"
118c2ecf20Sopenharmony_ci#include "../nfp_net.h"
128c2ecf20Sopenharmony_ci#include "../nfp_net_repr.h"
138c2ecf20Sopenharmony_ci#include "./cmsg.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic struct nfp_flower_cmsg_hdr *
168c2ecf20Sopenharmony_cinfp_flower_cmsg_get_hdr(struct sk_buff *skb)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	return (struct nfp_flower_cmsg_hdr *)skb->data;
198c2ecf20Sopenharmony_ci}
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct sk_buff *
228c2ecf20Sopenharmony_cinfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size,
238c2ecf20Sopenharmony_ci		      enum nfp_flower_cmsg_type_port type, gfp_t flag)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_hdr *ch;
268c2ecf20Sopenharmony_ci	struct sk_buff *skb;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	size += NFP_FLOWER_CMSG_HLEN;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	skb = nfp_app_ctrl_msg_alloc(app, size, flag);
318c2ecf20Sopenharmony_ci	if (!skb)
328c2ecf20Sopenharmony_ci		return NULL;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	ch = nfp_flower_cmsg_get_hdr(skb);
358c2ecf20Sopenharmony_ci	ch->pad = 0;
368c2ecf20Sopenharmony_ci	ch->version = NFP_FLOWER_CMSG_VER1;
378c2ecf20Sopenharmony_ci	ch->type = type;
388c2ecf20Sopenharmony_ci	skb_put(skb, size);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	return skb;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct sk_buff *
448c2ecf20Sopenharmony_cinfp_flower_cmsg_mac_repr_start(struct nfp_app *app, unsigned int num_ports)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_mac_repr *msg;
478c2ecf20Sopenharmony_ci	struct sk_buff *skb;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	skb = nfp_flower_cmsg_alloc(app, struct_size(msg, ports, num_ports),
508c2ecf20Sopenharmony_ci				    NFP_FLOWER_CMSG_TYPE_MAC_REPR, GFP_KERNEL);
518c2ecf20Sopenharmony_ci	if (!skb)
528c2ecf20Sopenharmony_ci		return NULL;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
558c2ecf20Sopenharmony_ci	memset(msg->reserved, 0, sizeof(msg->reserved));
568c2ecf20Sopenharmony_ci	msg->num_ports = num_ports;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return skb;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_civoid
628c2ecf20Sopenharmony_cinfp_flower_cmsg_mac_repr_add(struct sk_buff *skb, unsigned int idx,
638c2ecf20Sopenharmony_ci			     unsigned int nbi, unsigned int nbi_port,
648c2ecf20Sopenharmony_ci			     unsigned int phys_port)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_mac_repr *msg;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
698c2ecf20Sopenharmony_ci	msg->ports[idx].idx = idx;
708c2ecf20Sopenharmony_ci	msg->ports[idx].info = nbi & NFP_FLOWER_CMSG_MAC_REPR_NBI;
718c2ecf20Sopenharmony_ci	msg->ports[idx].nbi_port = nbi_port;
728c2ecf20Sopenharmony_ci	msg->ports[idx].phys_port = phys_port;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciint nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok,
768c2ecf20Sopenharmony_ci			    unsigned int mtu, bool mtu_only)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_portmod *msg;
798c2ecf20Sopenharmony_ci	struct sk_buff *skb;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	skb = nfp_flower_cmsg_alloc(repr->app, sizeof(*msg),
828c2ecf20Sopenharmony_ci				    NFP_FLOWER_CMSG_TYPE_PORT_MOD, GFP_KERNEL);
838c2ecf20Sopenharmony_ci	if (!skb)
848c2ecf20Sopenharmony_ci		return -ENOMEM;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
878c2ecf20Sopenharmony_ci	msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id);
888c2ecf20Sopenharmony_ci	msg->reserved = 0;
898c2ecf20Sopenharmony_ci	msg->info = carrier_ok;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (mtu_only)
928c2ecf20Sopenharmony_ci		msg->info |= NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	msg->mtu = cpu_to_be16(mtu);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	nfp_ctrl_tx(repr->app->ctrl, skb);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return 0;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ciint nfp_flower_cmsg_portreify(struct nfp_repr *repr, bool exists)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_portreify *msg;
1048c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	skb = nfp_flower_cmsg_alloc(repr->app, sizeof(*msg),
1078c2ecf20Sopenharmony_ci				    NFP_FLOWER_CMSG_TYPE_PORT_REIFY,
1088c2ecf20Sopenharmony_ci				    GFP_KERNEL);
1098c2ecf20Sopenharmony_ci	if (!skb)
1108c2ecf20Sopenharmony_ci		return -ENOMEM;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
1138c2ecf20Sopenharmony_ci	msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id);
1148c2ecf20Sopenharmony_ci	msg->reserved = 0;
1158c2ecf20Sopenharmony_ci	msg->info = cpu_to_be16(exists);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	nfp_ctrl_tx(repr->app->ctrl, skb);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic bool
1238c2ecf20Sopenharmony_cinfp_flower_process_mtu_ack(struct nfp_app *app, struct sk_buff *skb)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct nfp_flower_priv *app_priv = app->priv;
1268c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_portmod *msg;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (!(msg->info & NFP_FLOWER_CMSG_PORTMOD_MTU_CHANGE_ONLY))
1318c2ecf20Sopenharmony_ci		return false;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	spin_lock_bh(&app_priv->mtu_conf.lock);
1348c2ecf20Sopenharmony_ci	if (!app_priv->mtu_conf.requested_val ||
1358c2ecf20Sopenharmony_ci	    app_priv->mtu_conf.portnum != be32_to_cpu(msg->portnum) ||
1368c2ecf20Sopenharmony_ci	    be16_to_cpu(msg->mtu) != app_priv->mtu_conf.requested_val) {
1378c2ecf20Sopenharmony_ci		/* Not an ack for requested MTU change. */
1388c2ecf20Sopenharmony_ci		spin_unlock_bh(&app_priv->mtu_conf.lock);
1398c2ecf20Sopenharmony_ci		return false;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	app_priv->mtu_conf.ack = true;
1438c2ecf20Sopenharmony_ci	app_priv->mtu_conf.requested_val = 0;
1448c2ecf20Sopenharmony_ci	wake_up(&app_priv->mtu_conf.wait_q);
1458c2ecf20Sopenharmony_ci	spin_unlock_bh(&app_priv->mtu_conf.lock);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	return true;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic void
1518c2ecf20Sopenharmony_cinfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_portmod *msg;
1548c2ecf20Sopenharmony_ci	struct net_device *netdev;
1558c2ecf20Sopenharmony_ci	bool link;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
1588c2ecf20Sopenharmony_ci	link = msg->info & NFP_FLOWER_CMSG_PORTMOD_INFO_LINK;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	rtnl_lock();
1618c2ecf20Sopenharmony_ci	rcu_read_lock();
1628c2ecf20Sopenharmony_ci	netdev = nfp_app_dev_get(app, be32_to_cpu(msg->portnum), NULL);
1638c2ecf20Sopenharmony_ci	rcu_read_unlock();
1648c2ecf20Sopenharmony_ci	if (!netdev) {
1658c2ecf20Sopenharmony_ci		nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n",
1668c2ecf20Sopenharmony_ci				     be32_to_cpu(msg->portnum));
1678c2ecf20Sopenharmony_ci		rtnl_unlock();
1688c2ecf20Sopenharmony_ci		return;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (link) {
1728c2ecf20Sopenharmony_ci		u16 mtu = be16_to_cpu(msg->mtu);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		netif_carrier_on(netdev);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		/* An MTU of 0 from the firmware should be ignored */
1778c2ecf20Sopenharmony_ci		if (mtu)
1788c2ecf20Sopenharmony_ci			dev_set_mtu(netdev, mtu);
1798c2ecf20Sopenharmony_ci	} else {
1808c2ecf20Sopenharmony_ci		netif_carrier_off(netdev);
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci	rtnl_unlock();
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic void
1868c2ecf20Sopenharmony_cinfp_flower_cmsg_portreify_rx(struct nfp_app *app, struct sk_buff *skb)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct nfp_flower_priv *priv = app->priv;
1898c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_portreify *msg;
1908c2ecf20Sopenharmony_ci	bool exists;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	rcu_read_lock();
1958c2ecf20Sopenharmony_ci	exists = !!nfp_app_dev_get(app, be32_to_cpu(msg->portnum), NULL);
1968c2ecf20Sopenharmony_ci	rcu_read_unlock();
1978c2ecf20Sopenharmony_ci	if (!exists) {
1988c2ecf20Sopenharmony_ci		nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n",
1998c2ecf20Sopenharmony_ci				     be32_to_cpu(msg->portnum));
2008c2ecf20Sopenharmony_ci		return;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	atomic_inc(&priv->reify_replies);
2048c2ecf20Sopenharmony_ci	wake_up(&priv->reify_wait_queue);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic void
2088c2ecf20Sopenharmony_cinfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb);
2118c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_merge_hint *msg;
2128c2ecf20Sopenharmony_ci	struct nfp_fl_payload *sub_flows[2];
2138c2ecf20Sopenharmony_ci	int err, i, flow_cnt;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	msg = nfp_flower_cmsg_get_data(skb);
2168c2ecf20Sopenharmony_ci	/* msg->count starts at 0 and always assumes at least 1 entry. */
2178c2ecf20Sopenharmony_ci	flow_cnt = msg->count + 1;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (msg_len < struct_size(msg, flow, flow_cnt)) {
2208c2ecf20Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Merge hint ctrl msg too short - %d bytes but expect %zd\n",
2218c2ecf20Sopenharmony_ci				     msg_len, struct_size(msg, flow, flow_cnt));
2228c2ecf20Sopenharmony_ci		return;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (flow_cnt != 2) {
2268c2ecf20Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Merge hint contains %d flows - two are expected\n",
2278c2ecf20Sopenharmony_ci				     flow_cnt);
2288c2ecf20Sopenharmony_ci		return;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	rtnl_lock();
2328c2ecf20Sopenharmony_ci	for (i = 0; i < flow_cnt; i++) {
2338c2ecf20Sopenharmony_ci		u32 ctx = be32_to_cpu(msg->flow[i].host_ctx);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		sub_flows[i] = nfp_flower_get_fl_payload_from_ctx(app, ctx);
2368c2ecf20Sopenharmony_ci		if (!sub_flows[i]) {
2378c2ecf20Sopenharmony_ci			nfp_flower_cmsg_warn(app, "Invalid flow in merge hint\n");
2388c2ecf20Sopenharmony_ci			goto err_rtnl_unlock;
2398c2ecf20Sopenharmony_ci		}
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	err = nfp_flower_merge_offloaded_flows(app, sub_flows[0], sub_flows[1]);
2438c2ecf20Sopenharmony_ci	/* Only warn on memory fail. Hint veto will not break functionality. */
2448c2ecf20Sopenharmony_ci	if (err == -ENOMEM)
2458c2ecf20Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Flow merge memory fail.\n");
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cierr_rtnl_unlock:
2488c2ecf20Sopenharmony_ci	rtnl_unlock();
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic void
2528c2ecf20Sopenharmony_cinfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct nfp_flower_priv *app_priv = app->priv;
2558c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_hdr *cmsg_hdr;
2568c2ecf20Sopenharmony_ci	enum nfp_flower_cmsg_type_port type;
2578c2ecf20Sopenharmony_ci	bool skb_stored = false;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	cmsg_hdr = nfp_flower_cmsg_get_hdr(skb);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	type = cmsg_hdr->type;
2628c2ecf20Sopenharmony_ci	switch (type) {
2638c2ecf20Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_PORT_MOD:
2648c2ecf20Sopenharmony_ci		nfp_flower_cmsg_portmod_rx(app, skb);
2658c2ecf20Sopenharmony_ci		break;
2668c2ecf20Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_MERGE_HINT:
2678c2ecf20Sopenharmony_ci		if (app_priv->flower_en_feats & NFP_FL_ENABLE_FLOW_MERGE) {
2688c2ecf20Sopenharmony_ci			nfp_flower_cmsg_merge_hint_rx(app, skb);
2698c2ecf20Sopenharmony_ci			break;
2708c2ecf20Sopenharmony_ci		}
2718c2ecf20Sopenharmony_ci		goto err_default;
2728c2ecf20Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_NO_NEIGH:
2738c2ecf20Sopenharmony_ci		nfp_tunnel_request_route_v4(app, skb);
2748c2ecf20Sopenharmony_ci		break;
2758c2ecf20Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_NO_NEIGH_V6:
2768c2ecf20Sopenharmony_ci		nfp_tunnel_request_route_v6(app, skb);
2778c2ecf20Sopenharmony_ci		break;
2788c2ecf20Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_ACTIVE_TUNS:
2798c2ecf20Sopenharmony_ci		nfp_tunnel_keep_alive(app, skb);
2808c2ecf20Sopenharmony_ci		break;
2818c2ecf20Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_ACTIVE_TUNS_V6:
2828c2ecf20Sopenharmony_ci		nfp_tunnel_keep_alive_v6(app, skb);
2838c2ecf20Sopenharmony_ci		break;
2848c2ecf20Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_QOS_STATS:
2858c2ecf20Sopenharmony_ci		nfp_flower_stats_rlim_reply(app, skb);
2868c2ecf20Sopenharmony_ci		break;
2878c2ecf20Sopenharmony_ci	case NFP_FLOWER_CMSG_TYPE_LAG_CONFIG:
2888c2ecf20Sopenharmony_ci		if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) {
2898c2ecf20Sopenharmony_ci			skb_stored = nfp_flower_lag_unprocessed_msg(app, skb);
2908c2ecf20Sopenharmony_ci			break;
2918c2ecf20Sopenharmony_ci		}
2928c2ecf20Sopenharmony_ci		fallthrough;
2938c2ecf20Sopenharmony_ci	default:
2948c2ecf20Sopenharmony_cierr_default:
2958c2ecf20Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Cannot handle invalid repr control type %u\n",
2968c2ecf20Sopenharmony_ci				     type);
2978c2ecf20Sopenharmony_ci		goto out;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (!skb_stored)
3018c2ecf20Sopenharmony_ci		dev_consume_skb_any(skb);
3028c2ecf20Sopenharmony_ci	return;
3038c2ecf20Sopenharmony_ciout:
3048c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_civoid nfp_flower_cmsg_process_rx(struct work_struct *work)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct sk_buff_head cmsg_joined;
3108c2ecf20Sopenharmony_ci	struct nfp_flower_priv *priv;
3118c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	priv = container_of(work, struct nfp_flower_priv, cmsg_work);
3148c2ecf20Sopenharmony_ci	skb_queue_head_init(&cmsg_joined);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	spin_lock_bh(&priv->cmsg_skbs_high.lock);
3178c2ecf20Sopenharmony_ci	skb_queue_splice_tail_init(&priv->cmsg_skbs_high, &cmsg_joined);
3188c2ecf20Sopenharmony_ci	spin_unlock_bh(&priv->cmsg_skbs_high.lock);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	spin_lock_bh(&priv->cmsg_skbs_low.lock);
3218c2ecf20Sopenharmony_ci	skb_queue_splice_tail_init(&priv->cmsg_skbs_low, &cmsg_joined);
3228c2ecf20Sopenharmony_ci	spin_unlock_bh(&priv->cmsg_skbs_low.lock);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&cmsg_joined)))
3258c2ecf20Sopenharmony_ci		nfp_flower_cmsg_process_one_rx(priv->app, skb);
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic void
3298c2ecf20Sopenharmony_cinfp_flower_queue_ctl_msg(struct nfp_app *app, struct sk_buff *skb, int type)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct nfp_flower_priv *priv = app->priv;
3328c2ecf20Sopenharmony_ci	struct sk_buff_head *skb_head;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (type == NFP_FLOWER_CMSG_TYPE_PORT_MOD)
3358c2ecf20Sopenharmony_ci		skb_head = &priv->cmsg_skbs_high;
3368c2ecf20Sopenharmony_ci	else
3378c2ecf20Sopenharmony_ci		skb_head = &priv->cmsg_skbs_low;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (skb_queue_len(skb_head) >= NFP_FLOWER_WORKQ_MAX_SKBS) {
3408c2ecf20Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Dropping queued control messages\n");
3418c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
3428c2ecf20Sopenharmony_ci		return;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	skb_queue_tail(skb_head, skb);
3468c2ecf20Sopenharmony_ci	schedule_work(&priv->cmsg_work);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_civoid nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct nfp_flower_cmsg_hdr *cmsg_hdr;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	cmsg_hdr = nfp_flower_cmsg_get_hdr(skb);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (unlikely(cmsg_hdr->version != NFP_FLOWER_CMSG_VER1)) {
3568c2ecf20Sopenharmony_ci		nfp_flower_cmsg_warn(app, "Cannot handle repr control version %u\n",
3578c2ecf20Sopenharmony_ci				     cmsg_hdr->version);
3588c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
3598c2ecf20Sopenharmony_ci		return;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_FLOW_STATS) {
3638c2ecf20Sopenharmony_ci		/* We need to deal with stats updates from HW asap */
3648c2ecf20Sopenharmony_ci		nfp_flower_rx_flow_stats(app, skb);
3658c2ecf20Sopenharmony_ci		dev_consume_skb_any(skb);
3668c2ecf20Sopenharmony_ci	} else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_PORT_MOD &&
3678c2ecf20Sopenharmony_ci		   nfp_flower_process_mtu_ack(app, skb)) {
3688c2ecf20Sopenharmony_ci		/* Handle MTU acks outside wq to prevent RTNL conflict. */
3698c2ecf20Sopenharmony_ci		dev_consume_skb_any(skb);
3708c2ecf20Sopenharmony_ci	} else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH ||
3718c2ecf20Sopenharmony_ci		   cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6) {
3728c2ecf20Sopenharmony_ci		/* Acks from the NFP that the route is added - ignore. */
3738c2ecf20Sopenharmony_ci		dev_consume_skb_any(skb);
3748c2ecf20Sopenharmony_ci	} else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_PORT_REIFY) {
3758c2ecf20Sopenharmony_ci		/* Handle REIFY acks outside wq to prevent RTNL conflict. */
3768c2ecf20Sopenharmony_ci		nfp_flower_cmsg_portreify_rx(app, skb);
3778c2ecf20Sopenharmony_ci		dev_consume_skb_any(skb);
3788c2ecf20Sopenharmony_ci	} else {
3798c2ecf20Sopenharmony_ci		nfp_flower_queue_ctl_msg(app, skb, cmsg_hdr->type);
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci}
382