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