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