162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/etherdevice.h> 562306a36Sopenharmony_ci#include <linux/lockdep.h> 662306a36Sopenharmony_ci#include <linux/pci.h> 762306a36Sopenharmony_ci#include <linux/skbuff.h> 862306a36Sopenharmony_ci#include <linux/vmalloc.h> 962306a36Sopenharmony_ci#include <net/devlink.h> 1062306a36Sopenharmony_ci#include <net/dst_metadata.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "main.h" 1362306a36Sopenharmony_ci#include "../nfpcore/nfp_cpp.h" 1462306a36Sopenharmony_ci#include "../nfpcore/nfp_nffw.h" 1562306a36Sopenharmony_ci#include "../nfpcore/nfp_nsp.h" 1662306a36Sopenharmony_ci#include "../nfp_app.h" 1762306a36Sopenharmony_ci#include "../nfp_main.h" 1862306a36Sopenharmony_ci#include "../nfp_net.h" 1962306a36Sopenharmony_ci#include "../nfp_net_repr.h" 2062306a36Sopenharmony_ci#include "../nfp_port.h" 2162306a36Sopenharmony_ci#include "./cmsg.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define NFP_MIN_INT_PORT_ID 1 2662306a36Sopenharmony_ci#define NFP_MAX_INT_PORT_ID 256 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci return "FLOWER"; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci return DEVLINK_ESWITCH_MODE_SWITCHDEV; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int 3962306a36Sopenharmony_cinfp_flower_lookup_internal_port_id(struct nfp_flower_priv *priv, 4062306a36Sopenharmony_ci struct net_device *netdev) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct net_device *entry; 4362306a36Sopenharmony_ci int i, id = 0; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci rcu_read_lock(); 4662306a36Sopenharmony_ci idr_for_each_entry(&priv->internal_ports.port_ids, entry, i) 4762306a36Sopenharmony_ci if (entry == netdev) { 4862306a36Sopenharmony_ci id = i; 4962306a36Sopenharmony_ci break; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci rcu_read_unlock(); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return id; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int 5762306a36Sopenharmony_cinfp_flower_get_internal_port_id(struct nfp_app *app, struct net_device *netdev) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 6062306a36Sopenharmony_ci int id; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci id = nfp_flower_lookup_internal_port_id(priv, netdev); 6362306a36Sopenharmony_ci if (id > 0) 6462306a36Sopenharmony_ci return id; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci idr_preload(GFP_ATOMIC); 6762306a36Sopenharmony_ci spin_lock_bh(&priv->internal_ports.lock); 6862306a36Sopenharmony_ci id = idr_alloc(&priv->internal_ports.port_ids, netdev, 6962306a36Sopenharmony_ci NFP_MIN_INT_PORT_ID, NFP_MAX_INT_PORT_ID, GFP_ATOMIC); 7062306a36Sopenharmony_ci spin_unlock_bh(&priv->internal_ports.lock); 7162306a36Sopenharmony_ci idr_preload_end(); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return id; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciu32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app, 7762306a36Sopenharmony_ci struct net_device *netdev) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 8062306a36Sopenharmony_ci int ext_port; 8162306a36Sopenharmony_ci int gid; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (nfp_netdev_is_nfp_repr(netdev)) { 8462306a36Sopenharmony_ci return nfp_repr_get_port_id(netdev); 8562306a36Sopenharmony_ci } else if (nfp_flower_internal_port_can_offload(app, netdev)) { 8662306a36Sopenharmony_ci ext_port = nfp_flower_get_internal_port_id(app, netdev); 8762306a36Sopenharmony_ci if (ext_port < 0) 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return nfp_flower_internal_port_get_port_id(ext_port); 9162306a36Sopenharmony_ci } else if (netif_is_lag_master(netdev) && 9262306a36Sopenharmony_ci priv->flower_ext_feats & NFP_FL_FEATS_TUNNEL_NEIGH_LAG) { 9362306a36Sopenharmony_ci gid = nfp_flower_lag_get_output_id(app, netdev); 9462306a36Sopenharmony_ci if (gid < 0) 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return (NFP_FL_LAG_OUT | gid); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic struct net_device * 10462306a36Sopenharmony_cinfp_flower_get_netdev_from_internal_port_id(struct nfp_app *app, int port_id) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 10762306a36Sopenharmony_ci struct net_device *netdev; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci rcu_read_lock(); 11062306a36Sopenharmony_ci netdev = idr_find(&priv->internal_ports.port_ids, port_id); 11162306a36Sopenharmony_ci rcu_read_unlock(); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return netdev; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void 11762306a36Sopenharmony_cinfp_flower_free_internal_port_id(struct nfp_app *app, struct net_device *netdev) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 12062306a36Sopenharmony_ci int id; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci id = nfp_flower_lookup_internal_port_id(priv, netdev); 12362306a36Sopenharmony_ci if (!id) 12462306a36Sopenharmony_ci return; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci spin_lock_bh(&priv->internal_ports.lock); 12762306a36Sopenharmony_ci idr_remove(&priv->internal_ports.port_ids, id); 12862306a36Sopenharmony_ci spin_unlock_bh(&priv->internal_ports.lock); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int 13262306a36Sopenharmony_cinfp_flower_internal_port_event_handler(struct nfp_app *app, 13362306a36Sopenharmony_ci struct net_device *netdev, 13462306a36Sopenharmony_ci unsigned long event) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci if (event == NETDEV_UNREGISTER && 13762306a36Sopenharmony_ci nfp_flower_internal_port_can_offload(app, netdev)) 13862306a36Sopenharmony_ci nfp_flower_free_internal_port_id(app, netdev); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return NOTIFY_OK; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void nfp_flower_internal_port_init(struct nfp_flower_priv *priv) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci spin_lock_init(&priv->internal_ports.lock); 14662306a36Sopenharmony_ci idr_init(&priv->internal_ports.port_ids); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic void nfp_flower_internal_port_cleanup(struct nfp_flower_priv *priv) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci idr_destroy(&priv->internal_ports.port_ids); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic struct nfp_flower_non_repr_priv * 15562306a36Sopenharmony_cinfp_flower_non_repr_priv_lookup(struct nfp_app *app, struct net_device *netdev) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 15862306a36Sopenharmony_ci struct nfp_flower_non_repr_priv *entry; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ASSERT_RTNL(); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci list_for_each_entry(entry, &priv->non_repr_priv, list) 16362306a36Sopenharmony_ci if (entry->netdev == netdev) 16462306a36Sopenharmony_ci return entry; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return NULL; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_civoid 17062306a36Sopenharmony_ci__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci non_repr_priv->ref_count++; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistruct nfp_flower_non_repr_priv * 17662306a36Sopenharmony_cinfp_flower_non_repr_priv_get(struct nfp_app *app, struct net_device *netdev) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 17962306a36Sopenharmony_ci struct nfp_flower_non_repr_priv *entry; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci entry = nfp_flower_non_repr_priv_lookup(app, netdev); 18262306a36Sopenharmony_ci if (entry) 18362306a36Sopenharmony_ci goto inc_ref; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_KERNEL); 18662306a36Sopenharmony_ci if (!entry) 18762306a36Sopenharmony_ci return NULL; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci entry->netdev = netdev; 19062306a36Sopenharmony_ci list_add(&entry->list, &priv->non_repr_priv); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciinc_ref: 19362306a36Sopenharmony_ci __nfp_flower_non_repr_priv_get(entry); 19462306a36Sopenharmony_ci return entry; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid 19862306a36Sopenharmony_ci__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci if (--non_repr_priv->ref_count) 20162306a36Sopenharmony_ci return; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci list_del(&non_repr_priv->list); 20462306a36Sopenharmony_ci kfree(non_repr_priv); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_civoid 20862306a36Sopenharmony_cinfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct nfp_flower_non_repr_priv *entry; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci entry = nfp_flower_non_repr_priv_lookup(app, netdev); 21362306a36Sopenharmony_ci if (!entry) 21462306a36Sopenharmony_ci return; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci __nfp_flower_non_repr_priv_put(entry); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic enum nfp_repr_type 22062306a36Sopenharmony_cinfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci switch (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id)) { 22362306a36Sopenharmony_ci case NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT: 22462306a36Sopenharmony_ci *port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, 22562306a36Sopenharmony_ci port_id); 22662306a36Sopenharmony_ci return NFP_REPR_TYPE_PHYS_PORT; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci case NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT: 22962306a36Sopenharmony_ci *port = FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC, port_id); 23062306a36Sopenharmony_ci if (FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC_TYPE, port_id) == 23162306a36Sopenharmony_ci NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF) 23262306a36Sopenharmony_ci return NFP_REPR_TYPE_PF; 23362306a36Sopenharmony_ci else 23462306a36Sopenharmony_ci return NFP_REPR_TYPE_VF; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return __NFP_REPR_TYPE_MAX; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic struct net_device * 24162306a36Sopenharmony_cinfp_flower_dev_get(struct nfp_app *app, u32 port_id, bool *redir_egress) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci enum nfp_repr_type repr_type; 24462306a36Sopenharmony_ci struct nfp_reprs *reprs; 24562306a36Sopenharmony_ci u8 port = 0; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Check if the port is internal. */ 24862306a36Sopenharmony_ci if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id) == 24962306a36Sopenharmony_ci NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT) { 25062306a36Sopenharmony_ci if (redir_egress) 25162306a36Sopenharmony_ci *redir_egress = true; 25262306a36Sopenharmony_ci port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, port_id); 25362306a36Sopenharmony_ci return nfp_flower_get_netdev_from_internal_port_id(app, port); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port); 25762306a36Sopenharmony_ci if (repr_type > NFP_REPR_TYPE_MAX) 25862306a36Sopenharmony_ci return NULL; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci reprs = rcu_dereference(app->reprs[repr_type]); 26162306a36Sopenharmony_ci if (!reprs) 26262306a36Sopenharmony_ci return NULL; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (port >= reprs->num_reprs) 26562306a36Sopenharmony_ci return NULL; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return rcu_dereference(reprs->reprs[port]); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int 27162306a36Sopenharmony_cinfp_flower_reprs_reify(struct nfp_app *app, enum nfp_repr_type type, 27262306a36Sopenharmony_ci bool exists) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct nfp_reprs *reprs; 27562306a36Sopenharmony_ci int i, err, count = 0; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci reprs = rcu_dereference_protected(app->reprs[type], 27862306a36Sopenharmony_ci nfp_app_is_locked(app)); 27962306a36Sopenharmony_ci if (!reprs) 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci for (i = 0; i < reprs->num_reprs; i++) { 28362306a36Sopenharmony_ci struct net_device *netdev; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci netdev = nfp_repr_get_locked(app, reprs, i); 28662306a36Sopenharmony_ci if (netdev) { 28762306a36Sopenharmony_ci struct nfp_repr *repr = netdev_priv(netdev); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci err = nfp_flower_cmsg_portreify(repr, exists); 29062306a36Sopenharmony_ci if (err) 29162306a36Sopenharmony_ci return err; 29262306a36Sopenharmony_ci count++; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return count; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int 30062306a36Sopenharmony_cinfp_flower_wait_repr_reify(struct nfp_app *app, atomic_t *replies, int tot_repl) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!tot_repl) 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci assert_nfp_app_locked(app); 30862306a36Sopenharmony_ci if (!wait_event_timeout(priv->reify_wait_queue, 30962306a36Sopenharmony_ci atomic_read(replies) >= tot_repl, 31062306a36Sopenharmony_ci NFP_FL_REPLY_TIMEOUT)) { 31162306a36Sopenharmony_ci nfp_warn(app->cpp, "Not all reprs responded to reify\n"); 31262306a36Sopenharmony_ci return -EIO; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return 0; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int 31962306a36Sopenharmony_cinfp_flower_repr_netdev_open(struct nfp_app *app, struct nfp_repr *repr) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci int err; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci err = nfp_flower_cmsg_portmod(repr, true, repr->netdev->mtu, false); 32462306a36Sopenharmony_ci if (err) 32562306a36Sopenharmony_ci return err; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci netif_tx_wake_all_queues(repr->netdev); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int 33362306a36Sopenharmony_cinfp_flower_repr_netdev_stop(struct nfp_app *app, struct nfp_repr *repr) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci netif_tx_disable(repr->netdev); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return nfp_flower_cmsg_portmod(repr, false, repr->netdev->mtu, false); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void 34162306a36Sopenharmony_cinfp_flower_repr_netdev_clean(struct nfp_app *app, struct net_device *netdev) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct nfp_repr *repr = netdev_priv(netdev); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci kfree(repr->app_priv); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic void 34962306a36Sopenharmony_cinfp_flower_repr_netdev_preclean(struct nfp_app *app, struct net_device *netdev) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct nfp_repr *repr = netdev_priv(netdev); 35262306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 35362306a36Sopenharmony_ci atomic_t *replies = &priv->reify_replies; 35462306a36Sopenharmony_ci int err; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci atomic_set(replies, 0); 35762306a36Sopenharmony_ci err = nfp_flower_cmsg_portreify(repr, false); 35862306a36Sopenharmony_ci if (err) { 35962306a36Sopenharmony_ci nfp_warn(app->cpp, "Failed to notify firmware about repr destruction\n"); 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci nfp_flower_wait_repr_reify(app, replies, 1); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic void nfp_flower_sriov_disable(struct nfp_app *app) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (!priv->nn) 37162306a36Sopenharmony_ci return; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int 37762306a36Sopenharmony_cinfp_flower_spawn_vnic_reprs(struct nfp_app *app, 37862306a36Sopenharmony_ci enum nfp_flower_cmsg_port_vnic_type vnic_type, 37962306a36Sopenharmony_ci enum nfp_repr_type repr_type, unsigned int cnt) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci u8 nfp_pcie = nfp_cppcore_pcie_unit(app->pf->cpp); 38262306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 38362306a36Sopenharmony_ci atomic_t *replies = &priv->reify_replies; 38462306a36Sopenharmony_ci struct nfp_flower_repr_priv *repr_priv; 38562306a36Sopenharmony_ci enum nfp_port_type port_type; 38662306a36Sopenharmony_ci struct nfp_repr *nfp_repr; 38762306a36Sopenharmony_ci struct nfp_reprs *reprs; 38862306a36Sopenharmony_ci int i, err, reify_cnt; 38962306a36Sopenharmony_ci const u8 queue = 0; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci port_type = repr_type == NFP_REPR_TYPE_PF ? NFP_PORT_PF_PORT : 39262306a36Sopenharmony_ci NFP_PORT_VF_PORT; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci reprs = nfp_reprs_alloc(cnt); 39562306a36Sopenharmony_ci if (!reprs) 39662306a36Sopenharmony_ci return -ENOMEM; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 39962306a36Sopenharmony_ci struct net_device *repr; 40062306a36Sopenharmony_ci struct nfp_port *port; 40162306a36Sopenharmony_ci u32 port_id; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci repr = nfp_repr_alloc(app); 40462306a36Sopenharmony_ci if (!repr) { 40562306a36Sopenharmony_ci err = -ENOMEM; 40662306a36Sopenharmony_ci goto err_reprs_clean; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci repr_priv = kzalloc(sizeof(*repr_priv), GFP_KERNEL); 41062306a36Sopenharmony_ci if (!repr_priv) { 41162306a36Sopenharmony_ci err = -ENOMEM; 41262306a36Sopenharmony_ci nfp_repr_free(repr); 41362306a36Sopenharmony_ci goto err_reprs_clean; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci nfp_repr = netdev_priv(repr); 41762306a36Sopenharmony_ci nfp_repr->app_priv = repr_priv; 41862306a36Sopenharmony_ci repr_priv->nfp_repr = nfp_repr; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* For now we only support 1 PF */ 42162306a36Sopenharmony_ci WARN_ON(repr_type == NFP_REPR_TYPE_PF && i); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci port = nfp_port_alloc(app, port_type, repr); 42462306a36Sopenharmony_ci if (IS_ERR(port)) { 42562306a36Sopenharmony_ci err = PTR_ERR(port); 42662306a36Sopenharmony_ci kfree(repr_priv); 42762306a36Sopenharmony_ci nfp_repr_free(repr); 42862306a36Sopenharmony_ci goto err_reprs_clean; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci if (repr_type == NFP_REPR_TYPE_PF) { 43162306a36Sopenharmony_ci port->pf_id = i; 43262306a36Sopenharmony_ci port->vnic = priv->nn->dp.ctrl_bar; 43362306a36Sopenharmony_ci } else { 43462306a36Sopenharmony_ci port->pf_id = 0; 43562306a36Sopenharmony_ci port->vf_id = i; 43662306a36Sopenharmony_ci port->vnic = 43762306a36Sopenharmony_ci app->pf->vf_cfg_mem + i * NFP_NET_CFG_BAR_SZ; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci eth_hw_addr_random(repr); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type, 44362306a36Sopenharmony_ci i, queue); 44462306a36Sopenharmony_ci err = nfp_repr_init(app, repr, 44562306a36Sopenharmony_ci port_id, port, priv->nn->dp.netdev); 44662306a36Sopenharmony_ci if (err) { 44762306a36Sopenharmony_ci kfree(repr_priv); 44862306a36Sopenharmony_ci nfp_port_free(port); 44962306a36Sopenharmony_ci nfp_repr_free(repr); 45062306a36Sopenharmony_ci goto err_reprs_clean; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci RCU_INIT_POINTER(reprs->reprs[i], repr); 45462306a36Sopenharmony_ci nfp_info(app->cpp, "%s%d Representor(%s) created\n", 45562306a36Sopenharmony_ci repr_type == NFP_REPR_TYPE_PF ? "PF" : "VF", i, 45662306a36Sopenharmony_ci repr->name); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci nfp_app_reprs_set(app, repr_type, reprs); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci atomic_set(replies, 0); 46262306a36Sopenharmony_ci reify_cnt = nfp_flower_reprs_reify(app, repr_type, true); 46362306a36Sopenharmony_ci if (reify_cnt < 0) { 46462306a36Sopenharmony_ci err = reify_cnt; 46562306a36Sopenharmony_ci nfp_warn(app->cpp, "Failed to notify firmware about repr creation\n"); 46662306a36Sopenharmony_ci goto err_reprs_remove; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci err = nfp_flower_wait_repr_reify(app, replies, reify_cnt); 47062306a36Sopenharmony_ci if (err) 47162306a36Sopenharmony_ci goto err_reprs_remove; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_cierr_reprs_remove: 47562306a36Sopenharmony_ci reprs = nfp_app_reprs_set(app, repr_type, NULL); 47662306a36Sopenharmony_cierr_reprs_clean: 47762306a36Sopenharmony_ci nfp_reprs_clean_and_free(app, reprs); 47862306a36Sopenharmony_ci return err; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int nfp_flower_sriov_enable(struct nfp_app *app, int num_vfs) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (!priv->nn) 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return nfp_flower_spawn_vnic_reprs(app, 48962306a36Sopenharmony_ci NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF, 49062306a36Sopenharmony_ci NFP_REPR_TYPE_VF, num_vfs); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int 49462306a36Sopenharmony_cinfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct nfp_eth_table *eth_tbl = app->pf->eth_tbl; 49762306a36Sopenharmony_ci atomic_t *replies = &priv->reify_replies; 49862306a36Sopenharmony_ci struct nfp_flower_repr_priv *repr_priv; 49962306a36Sopenharmony_ci struct nfp_repr *nfp_repr; 50062306a36Sopenharmony_ci struct sk_buff *ctrl_skb; 50162306a36Sopenharmony_ci struct nfp_reprs *reprs; 50262306a36Sopenharmony_ci int err, reify_cnt; 50362306a36Sopenharmony_ci unsigned int i; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci ctrl_skb = nfp_flower_cmsg_mac_repr_start(app, eth_tbl->count); 50662306a36Sopenharmony_ci if (!ctrl_skb) 50762306a36Sopenharmony_ci return -ENOMEM; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci reprs = nfp_reprs_alloc(eth_tbl->max_index + 1); 51062306a36Sopenharmony_ci if (!reprs) { 51162306a36Sopenharmony_ci err = -ENOMEM; 51262306a36Sopenharmony_ci goto err_free_ctrl_skb; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci for (i = 0; i < eth_tbl->count; i++) { 51662306a36Sopenharmony_ci unsigned int phys_port = eth_tbl->ports[i].index; 51762306a36Sopenharmony_ci struct net_device *repr; 51862306a36Sopenharmony_ci struct nfp_port *port; 51962306a36Sopenharmony_ci u32 cmsg_port_id; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci repr = nfp_repr_alloc(app); 52262306a36Sopenharmony_ci if (!repr) { 52362306a36Sopenharmony_ci err = -ENOMEM; 52462306a36Sopenharmony_ci goto err_reprs_clean; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci repr_priv = kzalloc(sizeof(*repr_priv), GFP_KERNEL); 52862306a36Sopenharmony_ci if (!repr_priv) { 52962306a36Sopenharmony_ci err = -ENOMEM; 53062306a36Sopenharmony_ci nfp_repr_free(repr); 53162306a36Sopenharmony_ci goto err_reprs_clean; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci nfp_repr = netdev_priv(repr); 53562306a36Sopenharmony_ci nfp_repr->app_priv = repr_priv; 53662306a36Sopenharmony_ci repr_priv->nfp_repr = nfp_repr; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, repr); 53962306a36Sopenharmony_ci if (IS_ERR(port)) { 54062306a36Sopenharmony_ci err = PTR_ERR(port); 54162306a36Sopenharmony_ci kfree(repr_priv); 54262306a36Sopenharmony_ci nfp_repr_free(repr); 54362306a36Sopenharmony_ci goto err_reprs_clean; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci err = nfp_port_init_phy_port(app->pf, app, port, i); 54662306a36Sopenharmony_ci if (err) { 54762306a36Sopenharmony_ci kfree(repr_priv); 54862306a36Sopenharmony_ci nfp_port_free(port); 54962306a36Sopenharmony_ci nfp_repr_free(repr); 55062306a36Sopenharmony_ci goto err_reprs_clean; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci SET_NETDEV_DEV(repr, &priv->nn->pdev->dev); 55462306a36Sopenharmony_ci nfp_net_get_mac_addr(app->pf, repr, port); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port); 55762306a36Sopenharmony_ci err = nfp_repr_init(app, repr, 55862306a36Sopenharmony_ci cmsg_port_id, port, priv->nn->dp.netdev); 55962306a36Sopenharmony_ci if (err) { 56062306a36Sopenharmony_ci kfree(repr_priv); 56162306a36Sopenharmony_ci nfp_port_free(port); 56262306a36Sopenharmony_ci nfp_repr_free(repr); 56362306a36Sopenharmony_ci goto err_reprs_clean; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci nfp_flower_cmsg_mac_repr_add(ctrl_skb, i, 56762306a36Sopenharmony_ci eth_tbl->ports[i].nbi, 56862306a36Sopenharmony_ci eth_tbl->ports[i].base, 56962306a36Sopenharmony_ci phys_port); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci RCU_INIT_POINTER(reprs->reprs[phys_port], repr); 57262306a36Sopenharmony_ci nfp_info(app->cpp, "Phys Port %d Representor(%s) created\n", 57362306a36Sopenharmony_ci phys_port, repr->name); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* The REIFY/MAC_REPR control messages should be sent after the MAC 57962306a36Sopenharmony_ci * representors are registered using nfp_app_reprs_set(). This is 58062306a36Sopenharmony_ci * because the firmware may respond with control messages for the 58162306a36Sopenharmony_ci * MAC representors, f.e. to provide the driver with information 58262306a36Sopenharmony_ci * about their state, and without registration the driver will drop 58362306a36Sopenharmony_ci * any such messages. 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_ci atomic_set(replies, 0); 58662306a36Sopenharmony_ci reify_cnt = nfp_flower_reprs_reify(app, NFP_REPR_TYPE_PHYS_PORT, true); 58762306a36Sopenharmony_ci if (reify_cnt < 0) { 58862306a36Sopenharmony_ci err = reify_cnt; 58962306a36Sopenharmony_ci nfp_warn(app->cpp, "Failed to notify firmware about repr creation\n"); 59062306a36Sopenharmony_ci goto err_reprs_remove; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci err = nfp_flower_wait_repr_reify(app, replies, reify_cnt); 59462306a36Sopenharmony_ci if (err) 59562306a36Sopenharmony_ci goto err_reprs_remove; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci nfp_ctrl_tx(app->ctrl, ctrl_skb); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_cierr_reprs_remove: 60162306a36Sopenharmony_ci reprs = nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, NULL); 60262306a36Sopenharmony_cierr_reprs_clean: 60362306a36Sopenharmony_ci nfp_reprs_clean_and_free(app, reprs); 60462306a36Sopenharmony_cierr_free_ctrl_skb: 60562306a36Sopenharmony_ci kfree_skb(ctrl_skb); 60662306a36Sopenharmony_ci return err; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int nfp_flower_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, 61062306a36Sopenharmony_ci unsigned int id) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci if (id > 0) { 61362306a36Sopenharmony_ci nfp_warn(app->cpp, "FlowerNIC doesn't support more than one data vNIC\n"); 61462306a36Sopenharmony_ci goto err_invalid_port; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci eth_hw_addr_random(nn->dp.netdev); 61862306a36Sopenharmony_ci netif_keep_dst(nn->dp.netdev); 61962306a36Sopenharmony_ci nn->vnic_no_name = true; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci return 0; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cierr_invalid_port: 62462306a36Sopenharmony_ci nn->port = nfp_port_alloc(app, NFP_PORT_INVALID, nn->dp.netdev); 62562306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(nn->port); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic void nfp_flower_vnic_clean(struct nfp_app *app, struct nfp_net *nn) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (app->pf->num_vfs) 63362306a36Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF); 63462306a36Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF); 63562306a36Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci priv->nn = NULL; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 64362306a36Sopenharmony_ci int err; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci priv->nn = nn; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci err = nfp_flower_spawn_phy_reprs(app, app->priv); 64862306a36Sopenharmony_ci if (err) 64962306a36Sopenharmony_ci goto err_clear_nn; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci err = nfp_flower_spawn_vnic_reprs(app, 65262306a36Sopenharmony_ci NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF, 65362306a36Sopenharmony_ci NFP_REPR_TYPE_PF, 1); 65462306a36Sopenharmony_ci if (err) 65562306a36Sopenharmony_ci goto err_destroy_reprs_phy; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (app->pf->num_vfs) { 65862306a36Sopenharmony_ci err = nfp_flower_spawn_vnic_reprs(app, 65962306a36Sopenharmony_ci NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF, 66062306a36Sopenharmony_ci NFP_REPR_TYPE_VF, 66162306a36Sopenharmony_ci app->pf->num_vfs); 66262306a36Sopenharmony_ci if (err) 66362306a36Sopenharmony_ci goto err_destroy_reprs_pf; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci return 0; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cierr_destroy_reprs_pf: 66962306a36Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF); 67062306a36Sopenharmony_cierr_destroy_reprs_phy: 67162306a36Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); 67262306a36Sopenharmony_cierr_clear_nn: 67362306a36Sopenharmony_ci priv->nn = NULL; 67462306a36Sopenharmony_ci return err; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic void nfp_flower_wait_host_bit(struct nfp_app *app) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci unsigned long err_at; 68062306a36Sopenharmony_ci u64 feat; 68162306a36Sopenharmony_ci int err; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* Wait for HOST_ACK flag bit to propagate */ 68462306a36Sopenharmony_ci err_at = jiffies + msecs_to_jiffies(100); 68562306a36Sopenharmony_ci do { 68662306a36Sopenharmony_ci feat = nfp_rtsym_read_le(app->pf->rtbl, 68762306a36Sopenharmony_ci "_abi_flower_combined_features_global", 68862306a36Sopenharmony_ci &err); 68962306a36Sopenharmony_ci if (time_is_before_eq_jiffies(err_at)) { 69062306a36Sopenharmony_ci nfp_warn(app->cpp, 69162306a36Sopenharmony_ci "HOST_ACK bit not propagated in FW.\n"); 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci usleep_range(1000, 2000); 69562306a36Sopenharmony_ci } while (!err && !(feat & NFP_FL_FEATS_HOST_ACK)); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (err) 69862306a36Sopenharmony_ci nfp_warn(app->cpp, 69962306a36Sopenharmony_ci "Could not read global features entry from FW\n"); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic int nfp_flower_sync_feature_bits(struct nfp_app *app) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct nfp_flower_priv *app_priv = app->priv; 70562306a36Sopenharmony_ci int err; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Tell the firmware of the host supported features. */ 70862306a36Sopenharmony_ci err = nfp_rtsym_write_le(app->pf->rtbl, "_abi_flower_host_mask", 70962306a36Sopenharmony_ci app_priv->flower_ext_feats | 71062306a36Sopenharmony_ci NFP_FL_FEATS_HOST_ACK); 71162306a36Sopenharmony_ci if (!err) 71262306a36Sopenharmony_ci nfp_flower_wait_host_bit(app); 71362306a36Sopenharmony_ci else if (err != -ENOENT) 71462306a36Sopenharmony_ci return err; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* Tell the firmware that the driver supports lag. */ 71762306a36Sopenharmony_ci err = nfp_rtsym_write_le(app->pf->rtbl, 71862306a36Sopenharmony_ci "_abi_flower_balance_sync_enable", 1); 71962306a36Sopenharmony_ci if (!err) { 72062306a36Sopenharmony_ci app_priv->flower_en_feats |= NFP_FL_ENABLE_LAG; 72162306a36Sopenharmony_ci nfp_flower_lag_init(&app_priv->nfp_lag); 72262306a36Sopenharmony_ci } else if (err == -ENOENT) { 72362306a36Sopenharmony_ci nfp_warn(app->cpp, "LAG not supported by FW.\n"); 72462306a36Sopenharmony_ci } else { 72562306a36Sopenharmony_ci return err; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MOD) { 72962306a36Sopenharmony_ci /* Tell the firmware that the driver supports flow merging. */ 73062306a36Sopenharmony_ci err = nfp_rtsym_write_le(app->pf->rtbl, 73162306a36Sopenharmony_ci "_abi_flower_merge_hint_enable", 1); 73262306a36Sopenharmony_ci if (!err) { 73362306a36Sopenharmony_ci app_priv->flower_en_feats |= NFP_FL_ENABLE_FLOW_MERGE; 73462306a36Sopenharmony_ci nfp_flower_internal_port_init(app_priv); 73562306a36Sopenharmony_ci } else if (err == -ENOENT) { 73662306a36Sopenharmony_ci nfp_warn(app->cpp, 73762306a36Sopenharmony_ci "Flow merge not supported by FW.\n"); 73862306a36Sopenharmony_ci } else { 73962306a36Sopenharmony_ci return err; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } else { 74262306a36Sopenharmony_ci nfp_warn(app->cpp, "Flow mod/merge not supported by FW.\n"); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci return 0; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic int nfp_flower_init(struct nfp_app *app) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci u64 version, features, ctx_count, num_mems; 75162306a36Sopenharmony_ci const struct nfp_pf *pf = app->pf; 75262306a36Sopenharmony_ci struct nfp_flower_priv *app_priv; 75362306a36Sopenharmony_ci int err; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (!pf->eth_tbl) { 75662306a36Sopenharmony_ci nfp_warn(app->cpp, "FlowerNIC requires eth table\n"); 75762306a36Sopenharmony_ci return -EINVAL; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (!pf->mac_stats_bar) { 76162306a36Sopenharmony_ci nfp_warn(app->cpp, "FlowerNIC requires mac_stats BAR\n"); 76262306a36Sopenharmony_ci return -EINVAL; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (!pf->vf_cfg_bar) { 76662306a36Sopenharmony_ci nfp_warn(app->cpp, "FlowerNIC requires vf_cfg BAR\n"); 76762306a36Sopenharmony_ci return -EINVAL; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci version = nfp_rtsym_read_le(app->pf->rtbl, "hw_flower_version", &err); 77162306a36Sopenharmony_ci if (err) { 77262306a36Sopenharmony_ci nfp_warn(app->cpp, "FlowerNIC requires hw_flower_version memory symbol\n"); 77362306a36Sopenharmony_ci return err; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci num_mems = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_SPLIT", 77762306a36Sopenharmony_ci &err); 77862306a36Sopenharmony_ci if (err) { 77962306a36Sopenharmony_ci nfp_warn(app->cpp, 78062306a36Sopenharmony_ci "FlowerNIC: unsupported host context memory: %d\n", 78162306a36Sopenharmony_ci err); 78262306a36Sopenharmony_ci err = 0; 78362306a36Sopenharmony_ci num_mems = 1; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (!FIELD_FIT(NFP_FL_STAT_ID_MU_NUM, num_mems) || !num_mems) { 78762306a36Sopenharmony_ci nfp_warn(app->cpp, 78862306a36Sopenharmony_ci "FlowerNIC: invalid host context memory: %llu\n", 78962306a36Sopenharmony_ci num_mems); 79062306a36Sopenharmony_ci return -EINVAL; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci ctx_count = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_COUNT", 79462306a36Sopenharmony_ci &err); 79562306a36Sopenharmony_ci if (err) { 79662306a36Sopenharmony_ci nfp_warn(app->cpp, 79762306a36Sopenharmony_ci "FlowerNIC: unsupported host context count: %d\n", 79862306a36Sopenharmony_ci err); 79962306a36Sopenharmony_ci err = 0; 80062306a36Sopenharmony_ci ctx_count = BIT(17); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /* We need to ensure hardware has enough flower capabilities. */ 80462306a36Sopenharmony_ci if (version != NFP_FLOWER_ALLOWED_VER) { 80562306a36Sopenharmony_ci nfp_warn(app->cpp, "FlowerNIC: unsupported firmware version\n"); 80662306a36Sopenharmony_ci return -EINVAL; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci app_priv = vzalloc(sizeof(struct nfp_flower_priv)); 81062306a36Sopenharmony_ci if (!app_priv) 81162306a36Sopenharmony_ci return -ENOMEM; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci app_priv->total_mem_units = num_mems; 81462306a36Sopenharmony_ci app_priv->active_mem_unit = 0; 81562306a36Sopenharmony_ci app_priv->stats_ring_size = roundup_pow_of_two(ctx_count); 81662306a36Sopenharmony_ci app->priv = app_priv; 81762306a36Sopenharmony_ci app_priv->app = app; 81862306a36Sopenharmony_ci skb_queue_head_init(&app_priv->cmsg_skbs_high); 81962306a36Sopenharmony_ci skb_queue_head_init(&app_priv->cmsg_skbs_low); 82062306a36Sopenharmony_ci INIT_WORK(&app_priv->cmsg_work, nfp_flower_cmsg_process_rx); 82162306a36Sopenharmony_ci init_waitqueue_head(&app_priv->reify_wait_queue); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci init_waitqueue_head(&app_priv->mtu_conf.wait_q); 82462306a36Sopenharmony_ci spin_lock_init(&app_priv->mtu_conf.lock); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci err = nfp_flower_metadata_init(app, ctx_count, num_mems); 82762306a36Sopenharmony_ci if (err) 82862306a36Sopenharmony_ci goto err_free_app_priv; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* Extract the extra features supported by the firmware. */ 83162306a36Sopenharmony_ci features = nfp_rtsym_read_le(app->pf->rtbl, 83262306a36Sopenharmony_ci "_abi_flower_extra_features", &err); 83362306a36Sopenharmony_ci if (err) 83462306a36Sopenharmony_ci app_priv->flower_ext_feats = 0; 83562306a36Sopenharmony_ci else 83662306a36Sopenharmony_ci app_priv->flower_ext_feats = features & NFP_FL_FEATS_HOST; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci err = nfp_flower_sync_feature_bits(app); 83962306a36Sopenharmony_ci if (err) 84062306a36Sopenharmony_ci goto err_cleanup; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM) 84362306a36Sopenharmony_ci nfp_flower_qos_init(app); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci INIT_LIST_HEAD(&app_priv->indr_block_cb_priv); 84662306a36Sopenharmony_ci INIT_LIST_HEAD(&app_priv->non_repr_priv); 84762306a36Sopenharmony_ci app_priv->pre_tun_rule_cnt = 0; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci return 0; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cierr_cleanup: 85262306a36Sopenharmony_ci if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) 85362306a36Sopenharmony_ci nfp_flower_lag_cleanup(&app_priv->nfp_lag); 85462306a36Sopenharmony_ci nfp_flower_metadata_cleanup(app); 85562306a36Sopenharmony_cierr_free_app_priv: 85662306a36Sopenharmony_ci vfree(app->priv); 85762306a36Sopenharmony_ci return err; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic void nfp_flower_clean(struct nfp_app *app) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct nfp_flower_priv *app_priv = app->priv; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci skb_queue_purge(&app_priv->cmsg_skbs_high); 86562306a36Sopenharmony_ci skb_queue_purge(&app_priv->cmsg_skbs_low); 86662306a36Sopenharmony_ci flush_work(&app_priv->cmsg_work); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM) 86962306a36Sopenharmony_ci nfp_flower_qos_cleanup(app); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) 87262306a36Sopenharmony_ci nfp_flower_lag_cleanup(&app_priv->nfp_lag); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (app_priv->flower_en_feats & NFP_FL_ENABLE_FLOW_MERGE) 87562306a36Sopenharmony_ci nfp_flower_internal_port_cleanup(app_priv); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci nfp_flower_metadata_cleanup(app); 87862306a36Sopenharmony_ci vfree(app->priv); 87962306a36Sopenharmony_ci app->priv = NULL; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic bool nfp_flower_check_ack(struct nfp_flower_priv *app_priv) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci bool ret; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci spin_lock_bh(&app_priv->mtu_conf.lock); 88762306a36Sopenharmony_ci ret = app_priv->mtu_conf.ack; 88862306a36Sopenharmony_ci spin_unlock_bh(&app_priv->mtu_conf.lock); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci return ret; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic int 89462306a36Sopenharmony_cinfp_flower_repr_change_mtu(struct nfp_app *app, struct net_device *netdev, 89562306a36Sopenharmony_ci int new_mtu) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct nfp_flower_priv *app_priv = app->priv; 89862306a36Sopenharmony_ci struct nfp_repr *repr = netdev_priv(netdev); 89962306a36Sopenharmony_ci int err; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* Only need to config FW for physical port MTU change. */ 90262306a36Sopenharmony_ci if (repr->port->type != NFP_PORT_PHYS_PORT) 90362306a36Sopenharmony_ci return 0; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (!(app_priv->flower_ext_feats & NFP_FL_NBI_MTU_SETTING)) { 90662306a36Sopenharmony_ci nfp_err(app->cpp, "Physical port MTU setting not supported\n"); 90762306a36Sopenharmony_ci return -EINVAL; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci spin_lock_bh(&app_priv->mtu_conf.lock); 91162306a36Sopenharmony_ci app_priv->mtu_conf.ack = false; 91262306a36Sopenharmony_ci app_priv->mtu_conf.requested_val = new_mtu; 91362306a36Sopenharmony_ci app_priv->mtu_conf.portnum = repr->dst->u.port_info.port_id; 91462306a36Sopenharmony_ci spin_unlock_bh(&app_priv->mtu_conf.lock); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci err = nfp_flower_cmsg_portmod(repr, netif_carrier_ok(netdev), new_mtu, 91762306a36Sopenharmony_ci true); 91862306a36Sopenharmony_ci if (err) { 91962306a36Sopenharmony_ci spin_lock_bh(&app_priv->mtu_conf.lock); 92062306a36Sopenharmony_ci app_priv->mtu_conf.requested_val = 0; 92162306a36Sopenharmony_ci spin_unlock_bh(&app_priv->mtu_conf.lock); 92262306a36Sopenharmony_ci return err; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* Wait for fw to ack the change. */ 92662306a36Sopenharmony_ci if (!wait_event_timeout(app_priv->mtu_conf.wait_q, 92762306a36Sopenharmony_ci nfp_flower_check_ack(app_priv), 92862306a36Sopenharmony_ci NFP_FL_REPLY_TIMEOUT)) { 92962306a36Sopenharmony_ci spin_lock_bh(&app_priv->mtu_conf.lock); 93062306a36Sopenharmony_ci app_priv->mtu_conf.requested_val = 0; 93162306a36Sopenharmony_ci spin_unlock_bh(&app_priv->mtu_conf.lock); 93262306a36Sopenharmony_ci nfp_warn(app->cpp, "MTU change not verified with fw\n"); 93362306a36Sopenharmony_ci return -EIO; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return 0; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic int nfp_flower_start(struct nfp_app *app) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct nfp_flower_priv *app_priv = app->priv; 94262306a36Sopenharmony_ci int err; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) { 94562306a36Sopenharmony_ci err = nfp_flower_lag_reset(&app_priv->nfp_lag); 94662306a36Sopenharmony_ci if (err) 94762306a36Sopenharmony_ci return err; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci err = flow_indr_dev_register(nfp_flower_indr_setup_tc_cb, app); 95162306a36Sopenharmony_ci if (err) 95262306a36Sopenharmony_ci return err; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci err = nfp_tunnel_config_start(app); 95562306a36Sopenharmony_ci if (err) 95662306a36Sopenharmony_ci goto err_tunnel_config; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cierr_tunnel_config: 96162306a36Sopenharmony_ci flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app, 96262306a36Sopenharmony_ci nfp_flower_setup_indr_tc_release); 96362306a36Sopenharmony_ci return err; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic void nfp_flower_stop(struct nfp_app *app) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci nfp_tunnel_config_stop(app); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app, 97162306a36Sopenharmony_ci nfp_flower_setup_indr_tc_release); 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic int 97562306a36Sopenharmony_cinfp_flower_netdev_event(struct nfp_app *app, struct net_device *netdev, 97662306a36Sopenharmony_ci unsigned long event, void *ptr) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci struct nfp_flower_priv *app_priv = app->priv; 97962306a36Sopenharmony_ci int ret; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) { 98262306a36Sopenharmony_ci ret = nfp_flower_lag_netdev_event(app_priv, netdev, event, ptr); 98362306a36Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 98462306a36Sopenharmony_ci return ret; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci ret = nfp_flower_internal_port_event_handler(app, netdev, event); 98862306a36Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 98962306a36Sopenharmony_ci return ret; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return nfp_tunnel_mac_event_handler(app, netdev, event, ptr); 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ciconst struct nfp_app_type app_flower = { 99562306a36Sopenharmony_ci .id = NFP_APP_FLOWER_NIC, 99662306a36Sopenharmony_ci .name = "flower", 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci .ctrl_cap_mask = ~0U, 99962306a36Sopenharmony_ci .ctrl_has_meta = true, 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci .extra_cap = nfp_flower_extra_cap, 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci .init = nfp_flower_init, 100462306a36Sopenharmony_ci .clean = nfp_flower_clean, 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci .repr_change_mtu = nfp_flower_repr_change_mtu, 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci .vnic_alloc = nfp_flower_vnic_alloc, 100962306a36Sopenharmony_ci .vnic_init = nfp_flower_vnic_init, 101062306a36Sopenharmony_ci .vnic_clean = nfp_flower_vnic_clean, 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci .repr_preclean = nfp_flower_repr_netdev_preclean, 101362306a36Sopenharmony_ci .repr_clean = nfp_flower_repr_netdev_clean, 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci .repr_open = nfp_flower_repr_netdev_open, 101662306a36Sopenharmony_ci .repr_stop = nfp_flower_repr_netdev_stop, 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci .start = nfp_flower_start, 101962306a36Sopenharmony_ci .stop = nfp_flower_stop, 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci .netdev_event = nfp_flower_netdev_event, 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci .ctrl_msg_rx = nfp_flower_cmsg_rx, 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci .sriov_enable = nfp_flower_sriov_enable, 102662306a36Sopenharmony_ci .sriov_disable = nfp_flower_sriov_disable, 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci .eswitch_mode_get = eswitch_mode_get, 102962306a36Sopenharmony_ci .dev_get = nfp_flower_dev_get, 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci .setup_tc = nfp_flower_setup_tc, 103262306a36Sopenharmony_ci}; 1033