196de2506SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
296de2506SJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
31025351aSSimon Horman
41025351aSSimon Horman #include <linux/etherdevice.h>
5d2c2928dSDirk van der Merwe #include <linux/lockdep.h>
61025351aSSimon Horman #include <linux/pci.h>
71025351aSSimon Horman #include <linux/skbuff.h>
843f84b72SPieter Jansen van Vuuren #include <linux/vmalloc.h>
91025351aSSimon Horman #include <net/devlink.h>
101025351aSSimon Horman #include <net/dst_metadata.h>
111025351aSSimon Horman
128a276873SPieter Jansen van Vuuren #include "main.h"
131025351aSSimon Horman #include "../nfpcore/nfp_cpp.h"
148a276873SPieter Jansen van Vuuren #include "../nfpcore/nfp_nffw.h"
151025351aSSimon Horman #include "../nfpcore/nfp_nsp.h"
161025351aSSimon Horman #include "../nfp_app.h"
171025351aSSimon Horman #include "../nfp_main.h"
181025351aSSimon Horman #include "../nfp_net.h"
191025351aSSimon Horman #include "../nfp_net_repr.h"
201025351aSSimon Horman #include "../nfp_port.h"
211025351aSSimon Horman #include "./cmsg.h"
221025351aSSimon Horman
238a276873SPieter Jansen van Vuuren #define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL
248a276873SPieter Jansen van Vuuren
254d12ba42SJohn Hurley #define NFP_MIN_INT_PORT_ID 1
264d12ba42SJohn Hurley #define NFP_MAX_INT_PORT_ID 256
274d12ba42SJohn Hurley
nfp_flower_extra_cap(struct nfp_app * app,struct nfp_net * nn)281025351aSSimon Horman static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn)
291025351aSSimon Horman {
301025351aSSimon Horman return "FLOWER";
311025351aSSimon Horman }
321025351aSSimon Horman
eswitch_mode_get(struct nfp_app * app)331025351aSSimon Horman static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app)
341025351aSSimon Horman {
351025351aSSimon Horman return DEVLINK_ESWITCH_MODE_SWITCHDEV;
361025351aSSimon Horman }
371025351aSSimon Horman
384d12ba42SJohn Hurley static int
nfp_flower_lookup_internal_port_id(struct nfp_flower_priv * priv,struct net_device * netdev)394d12ba42SJohn Hurley nfp_flower_lookup_internal_port_id(struct nfp_flower_priv *priv,
404d12ba42SJohn Hurley struct net_device *netdev)
414d12ba42SJohn Hurley {
424d12ba42SJohn Hurley struct net_device *entry;
434d12ba42SJohn Hurley int i, id = 0;
444d12ba42SJohn Hurley
454d12ba42SJohn Hurley rcu_read_lock();
464d12ba42SJohn Hurley idr_for_each_entry(&priv->internal_ports.port_ids, entry, i)
474d12ba42SJohn Hurley if (entry == netdev) {
484d12ba42SJohn Hurley id = i;
494d12ba42SJohn Hurley break;
504d12ba42SJohn Hurley }
514d12ba42SJohn Hurley rcu_read_unlock();
524d12ba42SJohn Hurley
534d12ba42SJohn Hurley return id;
544d12ba42SJohn Hurley }
554d12ba42SJohn Hurley
564d12ba42SJohn Hurley static int
nfp_flower_get_internal_port_id(struct nfp_app * app,struct net_device * netdev)574d12ba42SJohn Hurley nfp_flower_get_internal_port_id(struct nfp_app *app, struct net_device *netdev)
584d12ba42SJohn Hurley {
594d12ba42SJohn Hurley struct nfp_flower_priv *priv = app->priv;
604d12ba42SJohn Hurley int id;
614d12ba42SJohn Hurley
624d12ba42SJohn Hurley id = nfp_flower_lookup_internal_port_id(priv, netdev);
634d12ba42SJohn Hurley if (id > 0)
644d12ba42SJohn Hurley return id;
654d12ba42SJohn Hurley
664d12ba42SJohn Hurley idr_preload(GFP_ATOMIC);
674d12ba42SJohn Hurley spin_lock_bh(&priv->internal_ports.lock);
684d12ba42SJohn Hurley id = idr_alloc(&priv->internal_ports.port_ids, netdev,
694d12ba42SJohn Hurley NFP_MIN_INT_PORT_ID, NFP_MAX_INT_PORT_ID, GFP_ATOMIC);
704d12ba42SJohn Hurley spin_unlock_bh(&priv->internal_ports.lock);
714d12ba42SJohn Hurley idr_preload_end();
724d12ba42SJohn Hurley
734d12ba42SJohn Hurley return id;
744d12ba42SJohn Hurley }
754d12ba42SJohn Hurley
nfp_flower_get_port_id_from_netdev(struct nfp_app * app,struct net_device * netdev)764d12ba42SJohn Hurley u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app,
774d12ba42SJohn Hurley struct net_device *netdev)
784d12ba42SJohn Hurley {
79*abc21095SYanguo Li struct nfp_flower_priv *priv = app->priv;
804d12ba42SJohn Hurley int ext_port;
81*abc21095SYanguo Li int gid;
824d12ba42SJohn Hurley
834d12ba42SJohn Hurley if (nfp_netdev_is_nfp_repr(netdev)) {
844d12ba42SJohn Hurley return nfp_repr_get_port_id(netdev);
854d12ba42SJohn Hurley } else if (nfp_flower_internal_port_can_offload(app, netdev)) {
864d12ba42SJohn Hurley ext_port = nfp_flower_get_internal_port_id(app, netdev);
874d12ba42SJohn Hurley if (ext_port < 0)
884d12ba42SJohn Hurley return 0;
894d12ba42SJohn Hurley
904d12ba42SJohn Hurley return nfp_flower_internal_port_get_port_id(ext_port);
91*abc21095SYanguo Li } else if (netif_is_lag_master(netdev) &&
92*abc21095SYanguo Li priv->flower_ext_feats & NFP_FL_FEATS_TUNNEL_NEIGH_LAG) {
93*abc21095SYanguo Li gid = nfp_flower_lag_get_output_id(app, netdev);
94*abc21095SYanguo Li if (gid < 0)
95*abc21095SYanguo Li return 0;
96*abc21095SYanguo Li
97*abc21095SYanguo Li return (NFP_FL_LAG_OUT | gid);
984d12ba42SJohn Hurley }
994d12ba42SJohn Hurley
1004d12ba42SJohn Hurley return 0;
1014d12ba42SJohn Hurley }
1024d12ba42SJohn Hurley
103f41dd059SJohn Hurley static struct net_device *
nfp_flower_get_netdev_from_internal_port_id(struct nfp_app * app,int port_id)104f41dd059SJohn Hurley nfp_flower_get_netdev_from_internal_port_id(struct nfp_app *app, int port_id)
105f41dd059SJohn Hurley {
106f41dd059SJohn Hurley struct nfp_flower_priv *priv = app->priv;
107f41dd059SJohn Hurley struct net_device *netdev;
108f41dd059SJohn Hurley
109f41dd059SJohn Hurley rcu_read_lock();
110f41dd059SJohn Hurley netdev = idr_find(&priv->internal_ports.port_ids, port_id);
111f41dd059SJohn Hurley rcu_read_unlock();
112f41dd059SJohn Hurley
113f41dd059SJohn Hurley return netdev;
114f41dd059SJohn Hurley }
115f41dd059SJohn Hurley
1164d12ba42SJohn Hurley static void
nfp_flower_free_internal_port_id(struct nfp_app * app,struct net_device * netdev)1174d12ba42SJohn Hurley nfp_flower_free_internal_port_id(struct nfp_app *app, struct net_device *netdev)
1184d12ba42SJohn Hurley {
1194d12ba42SJohn Hurley struct nfp_flower_priv *priv = app->priv;
1204d12ba42SJohn Hurley int id;
1214d12ba42SJohn Hurley
1224d12ba42SJohn Hurley id = nfp_flower_lookup_internal_port_id(priv, netdev);
1234d12ba42SJohn Hurley if (!id)
1244d12ba42SJohn Hurley return;
1254d12ba42SJohn Hurley
1264d12ba42SJohn Hurley spin_lock_bh(&priv->internal_ports.lock);
1274d12ba42SJohn Hurley idr_remove(&priv->internal_ports.port_ids, id);
1284d12ba42SJohn Hurley spin_unlock_bh(&priv->internal_ports.lock);
1294d12ba42SJohn Hurley }
1304d12ba42SJohn Hurley
1314d12ba42SJohn Hurley static int
nfp_flower_internal_port_event_handler(struct nfp_app * app,struct net_device * netdev,unsigned long event)1324d12ba42SJohn Hurley nfp_flower_internal_port_event_handler(struct nfp_app *app,
1334d12ba42SJohn Hurley struct net_device *netdev,
1344d12ba42SJohn Hurley unsigned long event)
1354d12ba42SJohn Hurley {
1364d12ba42SJohn Hurley if (event == NETDEV_UNREGISTER &&
1374d12ba42SJohn Hurley nfp_flower_internal_port_can_offload(app, netdev))
1384d12ba42SJohn Hurley nfp_flower_free_internal_port_id(app, netdev);
1394d12ba42SJohn Hurley
1404d12ba42SJohn Hurley return NOTIFY_OK;
1414d12ba42SJohn Hurley }
1424d12ba42SJohn Hurley
nfp_flower_internal_port_init(struct nfp_flower_priv * priv)1434d12ba42SJohn Hurley static void nfp_flower_internal_port_init(struct nfp_flower_priv *priv)
1444d12ba42SJohn Hurley {
1454d12ba42SJohn Hurley spin_lock_init(&priv->internal_ports.lock);
1464d12ba42SJohn Hurley idr_init(&priv->internal_ports.port_ids);
1474d12ba42SJohn Hurley }
1484d12ba42SJohn Hurley
nfp_flower_internal_port_cleanup(struct nfp_flower_priv * priv)1494d12ba42SJohn Hurley static void nfp_flower_internal_port_cleanup(struct nfp_flower_priv *priv)
1504d12ba42SJohn Hurley {
1514d12ba42SJohn Hurley idr_destroy(&priv->internal_ports.port_ids);
1524d12ba42SJohn Hurley }
1534d12ba42SJohn Hurley
15405d2bee6SJohn Hurley static struct nfp_flower_non_repr_priv *
nfp_flower_non_repr_priv_lookup(struct nfp_app * app,struct net_device * netdev)15505d2bee6SJohn Hurley nfp_flower_non_repr_priv_lookup(struct nfp_app *app, struct net_device *netdev)
15605d2bee6SJohn Hurley {
15705d2bee6SJohn Hurley struct nfp_flower_priv *priv = app->priv;
15805d2bee6SJohn Hurley struct nfp_flower_non_repr_priv *entry;
15905d2bee6SJohn Hurley
16005d2bee6SJohn Hurley ASSERT_RTNL();
16105d2bee6SJohn Hurley
16205d2bee6SJohn Hurley list_for_each_entry(entry, &priv->non_repr_priv, list)
16305d2bee6SJohn Hurley if (entry->netdev == netdev)
16405d2bee6SJohn Hurley return entry;
16505d2bee6SJohn Hurley
16605d2bee6SJohn Hurley return NULL;
16705d2bee6SJohn Hurley }
16805d2bee6SJohn Hurley
16905d2bee6SJohn Hurley void
__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv * non_repr_priv)17005d2bee6SJohn Hurley __nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv)
17105d2bee6SJohn Hurley {
17205d2bee6SJohn Hurley non_repr_priv->ref_count++;
17305d2bee6SJohn Hurley }
17405d2bee6SJohn Hurley
17505d2bee6SJohn Hurley struct nfp_flower_non_repr_priv *
nfp_flower_non_repr_priv_get(struct nfp_app * app,struct net_device * netdev)17605d2bee6SJohn Hurley nfp_flower_non_repr_priv_get(struct nfp_app *app, struct net_device *netdev)
17705d2bee6SJohn Hurley {
17805d2bee6SJohn Hurley struct nfp_flower_priv *priv = app->priv;
17905d2bee6SJohn Hurley struct nfp_flower_non_repr_priv *entry;
18005d2bee6SJohn Hurley
18105d2bee6SJohn Hurley entry = nfp_flower_non_repr_priv_lookup(app, netdev);
18205d2bee6SJohn Hurley if (entry)
18305d2bee6SJohn Hurley goto inc_ref;
18405d2bee6SJohn Hurley
18505d2bee6SJohn Hurley entry = kzalloc(sizeof(*entry), GFP_KERNEL);
18605d2bee6SJohn Hurley if (!entry)
18705d2bee6SJohn Hurley return NULL;
18805d2bee6SJohn Hurley
18905d2bee6SJohn Hurley entry->netdev = netdev;
19005d2bee6SJohn Hurley list_add(&entry->list, &priv->non_repr_priv);
19105d2bee6SJohn Hurley
19205d2bee6SJohn Hurley inc_ref:
19305d2bee6SJohn Hurley __nfp_flower_non_repr_priv_get(entry);
19405d2bee6SJohn Hurley return entry;
19505d2bee6SJohn Hurley }
19605d2bee6SJohn Hurley
19705d2bee6SJohn Hurley void
__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv * non_repr_priv)19805d2bee6SJohn Hurley __nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv)
19905d2bee6SJohn Hurley {
20005d2bee6SJohn Hurley if (--non_repr_priv->ref_count)
20105d2bee6SJohn Hurley return;
20205d2bee6SJohn Hurley
20305d2bee6SJohn Hurley list_del(&non_repr_priv->list);
20405d2bee6SJohn Hurley kfree(non_repr_priv);
20505d2bee6SJohn Hurley }
20605d2bee6SJohn Hurley
20705d2bee6SJohn Hurley void
nfp_flower_non_repr_priv_put(struct nfp_app * app,struct net_device * netdev)20805d2bee6SJohn Hurley nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev)
20905d2bee6SJohn Hurley {
21005d2bee6SJohn Hurley struct nfp_flower_non_repr_priv *entry;
21105d2bee6SJohn Hurley
21205d2bee6SJohn Hurley entry = nfp_flower_non_repr_priv_lookup(app, netdev);
21305d2bee6SJohn Hurley if (!entry)
21405d2bee6SJohn Hurley return;
21505d2bee6SJohn Hurley
21605d2bee6SJohn Hurley __nfp_flower_non_repr_priv_put(entry);
21705d2bee6SJohn Hurley }
21805d2bee6SJohn Hurley
2191025351aSSimon Horman static enum nfp_repr_type
nfp_flower_repr_get_type_and_port(struct nfp_app * app,u32 port_id,u8 * port)2201025351aSSimon Horman nfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port)
2211025351aSSimon Horman {
2221025351aSSimon Horman switch (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id)) {
2231025351aSSimon Horman case NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT:
2241025351aSSimon Horman *port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM,
2251025351aSSimon Horman port_id);
2261025351aSSimon Horman return NFP_REPR_TYPE_PHYS_PORT;
2271025351aSSimon Horman
2281025351aSSimon Horman case NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT:
2291025351aSSimon Horman *port = FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC, port_id);
2301025351aSSimon Horman if (FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC_TYPE, port_id) ==
2311025351aSSimon Horman NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF)
2321025351aSSimon Horman return NFP_REPR_TYPE_PF;
2331025351aSSimon Horman else
2341025351aSSimon Horman return NFP_REPR_TYPE_VF;
2351025351aSSimon Horman }
2361025351aSSimon Horman
237ee614c87SJohn Hurley return __NFP_REPR_TYPE_MAX;
2381025351aSSimon Horman }
2391025351aSSimon Horman
2401025351aSSimon Horman static struct net_device *
nfp_flower_dev_get(struct nfp_app * app,u32 port_id,bool * redir_egress)241f41dd059SJohn Hurley nfp_flower_dev_get(struct nfp_app *app, u32 port_id, bool *redir_egress)
2421025351aSSimon Horman {
2431025351aSSimon Horman enum nfp_repr_type repr_type;
2441025351aSSimon Horman struct nfp_reprs *reprs;
2451025351aSSimon Horman u8 port = 0;
2461025351aSSimon Horman
247f41dd059SJohn Hurley /* Check if the port is internal. */
248f41dd059SJohn Hurley if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id) ==
249f41dd059SJohn Hurley NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT) {
250f41dd059SJohn Hurley if (redir_egress)
251f41dd059SJohn Hurley *redir_egress = true;
252f41dd059SJohn Hurley port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, port_id);
253f41dd059SJohn Hurley return nfp_flower_get_netdev_from_internal_port_id(app, port);
254f41dd059SJohn Hurley }
255f41dd059SJohn Hurley
2561025351aSSimon Horman repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port);
257ee614c87SJohn Hurley if (repr_type > NFP_REPR_TYPE_MAX)
258ee614c87SJohn Hurley return NULL;
2591025351aSSimon Horman
2601025351aSSimon Horman reprs = rcu_dereference(app->reprs[repr_type]);
2611025351aSSimon Horman if (!reprs)
2621025351aSSimon Horman return NULL;
2631025351aSSimon Horman
2641025351aSSimon Horman if (port >= reprs->num_reprs)
2651025351aSSimon Horman return NULL;
2661025351aSSimon Horman
2673eb47dfcSJakub Kicinski return rcu_dereference(reprs->reprs[port]);
2681025351aSSimon Horman }
2691025351aSSimon Horman
2705d7c64a7SJakub Kicinski static int
nfp_flower_reprs_reify(struct nfp_app * app,enum nfp_repr_type type,bool exists)271d2c2928dSDirk van der Merwe nfp_flower_reprs_reify(struct nfp_app *app, enum nfp_repr_type type,
272d2c2928dSDirk van der Merwe bool exists)
273d2c2928dSDirk van der Merwe {
274d2c2928dSDirk van der Merwe struct nfp_reprs *reprs;
275d2c2928dSDirk van der Merwe int i, err, count = 0;
276d2c2928dSDirk van der Merwe
277d2c2928dSDirk van der Merwe reprs = rcu_dereference_protected(app->reprs[type],
2788a38f2ccSJakub Kicinski nfp_app_is_locked(app));
279d2c2928dSDirk van der Merwe if (!reprs)
280d2c2928dSDirk van der Merwe return 0;
281d2c2928dSDirk van der Merwe
2823eb47dfcSJakub Kicinski for (i = 0; i < reprs->num_reprs; i++) {
2833eb47dfcSJakub Kicinski struct net_device *netdev;
2843eb47dfcSJakub Kicinski
2853eb47dfcSJakub Kicinski netdev = nfp_repr_get_locked(app, reprs, i);
2863eb47dfcSJakub Kicinski if (netdev) {
2873eb47dfcSJakub Kicinski struct nfp_repr *repr = netdev_priv(netdev);
288d2c2928dSDirk van der Merwe
289d2c2928dSDirk van der Merwe err = nfp_flower_cmsg_portreify(repr, exists);
290d2c2928dSDirk van der Merwe if (err)
291d2c2928dSDirk van der Merwe return err;
292d2c2928dSDirk van der Merwe count++;
293d2c2928dSDirk van der Merwe }
2943eb47dfcSJakub Kicinski }
295d2c2928dSDirk van der Merwe
296d2c2928dSDirk van der Merwe return count;
297d2c2928dSDirk van der Merwe }
298d2c2928dSDirk van der Merwe
299d2c2928dSDirk van der Merwe static int
nfp_flower_wait_repr_reify(struct nfp_app * app,atomic_t * replies,int tot_repl)300d2c2928dSDirk van der Merwe nfp_flower_wait_repr_reify(struct nfp_app *app, atomic_t *replies, int tot_repl)
301d2c2928dSDirk van der Merwe {
302d2c2928dSDirk van der Merwe struct nfp_flower_priv *priv = app->priv;
303d2c2928dSDirk van der Merwe
304d2c2928dSDirk van der Merwe if (!tot_repl)
305d2c2928dSDirk van der Merwe return 0;
306d2c2928dSDirk van der Merwe
3078a38f2ccSJakub Kicinski assert_nfp_app_locked(app);
30896439889SFred Lotter if (!wait_event_timeout(priv->reify_wait_queue,
309d2c2928dSDirk van der Merwe atomic_read(replies) >= tot_repl,
31096439889SFred Lotter NFP_FL_REPLY_TIMEOUT)) {
311d2c2928dSDirk van der Merwe nfp_warn(app->cpp, "Not all reprs responded to reify\n");
312d2c2928dSDirk van der Merwe return -EIO;
313d2c2928dSDirk van der Merwe }
314d2c2928dSDirk van der Merwe
315d2c2928dSDirk van der Merwe return 0;
316d2c2928dSDirk van der Merwe }
317d2c2928dSDirk van der Merwe
318d2c2928dSDirk van der Merwe static int
nfp_flower_repr_netdev_open(struct nfp_app * app,struct nfp_repr * repr)3195d7c64a7SJakub Kicinski nfp_flower_repr_netdev_open(struct nfp_app *app, struct nfp_repr *repr)
3201025351aSSimon Horman {
3211025351aSSimon Horman int err;
3221025351aSSimon Horman
32329a5dcaeSJohn Hurley err = nfp_flower_cmsg_portmod(repr, true, repr->netdev->mtu, false);
3241025351aSSimon Horman if (err)
3251025351aSSimon Horman return err;
3261025351aSSimon Horman
3275d7c64a7SJakub Kicinski netif_tx_wake_all_queues(repr->netdev);
3281025351aSSimon Horman
3291025351aSSimon Horman return 0;
3301025351aSSimon Horman }
3311025351aSSimon Horman
3325d7c64a7SJakub Kicinski static int
nfp_flower_repr_netdev_stop(struct nfp_app * app,struct nfp_repr * repr)3335d7c64a7SJakub Kicinski nfp_flower_repr_netdev_stop(struct nfp_app *app, struct nfp_repr *repr)
3341025351aSSimon Horman {
3355d7c64a7SJakub Kicinski netif_tx_disable(repr->netdev);
3361025351aSSimon Horman
33729a5dcaeSJohn Hurley return nfp_flower_cmsg_portmod(repr, false, repr->netdev->mtu, false);
3381025351aSSimon Horman }
3391025351aSSimon Horman
3401a24d4f9SJohn Hurley static void
nfp_flower_repr_netdev_clean(struct nfp_app * app,struct net_device * netdev)3411a24d4f9SJohn Hurley nfp_flower_repr_netdev_clean(struct nfp_app *app, struct net_device *netdev)
3421a24d4f9SJohn Hurley {
343b9452452SJohn Hurley struct nfp_repr *repr = netdev_priv(netdev);
344b9452452SJohn Hurley
345b9452452SJohn Hurley kfree(repr->app_priv);
3461a24d4f9SJohn Hurley }
3471a24d4f9SJohn Hurley
348d2c2928dSDirk van der Merwe static void
nfp_flower_repr_netdev_preclean(struct nfp_app * app,struct net_device * netdev)349d2c2928dSDirk van der Merwe nfp_flower_repr_netdev_preclean(struct nfp_app *app, struct net_device *netdev)
350d2c2928dSDirk van der Merwe {
351d2c2928dSDirk van der Merwe struct nfp_repr *repr = netdev_priv(netdev);
352d2c2928dSDirk van der Merwe struct nfp_flower_priv *priv = app->priv;
353d2c2928dSDirk van der Merwe atomic_t *replies = &priv->reify_replies;
354d2c2928dSDirk van der Merwe int err;
355d2c2928dSDirk van der Merwe
356d2c2928dSDirk van der Merwe atomic_set(replies, 0);
357d2c2928dSDirk van der Merwe err = nfp_flower_cmsg_portreify(repr, false);
358d2c2928dSDirk van der Merwe if (err) {
359d2c2928dSDirk van der Merwe nfp_warn(app->cpp, "Failed to notify firmware about repr destruction\n");
360d2c2928dSDirk van der Merwe return;
361d2c2928dSDirk van der Merwe }
362d2c2928dSDirk van der Merwe
363d2c2928dSDirk van der Merwe nfp_flower_wait_repr_reify(app, replies, 1);
364d2c2928dSDirk van der Merwe }
365d2c2928dSDirk van der Merwe
nfp_flower_sriov_disable(struct nfp_app * app)36624a021edSSimon Horman static void nfp_flower_sriov_disable(struct nfp_app *app)
3671025351aSSimon Horman {
368192e6851SJakub Kicinski struct nfp_flower_priv *priv = app->priv;
369192e6851SJakub Kicinski
370192e6851SJakub Kicinski if (!priv->nn)
371192e6851SJakub Kicinski return;
372192e6851SJakub Kicinski
37324a021edSSimon Horman nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF);
3741025351aSSimon Horman }
3751025351aSSimon Horman
37624a021edSSimon Horman static int
nfp_flower_spawn_vnic_reprs(struct nfp_app * app,enum nfp_flower_cmsg_port_vnic_type vnic_type,enum nfp_repr_type repr_type,unsigned int cnt)37724a021edSSimon Horman nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
37824a021edSSimon Horman enum nfp_flower_cmsg_port_vnic_type vnic_type,
37924a021edSSimon Horman enum nfp_repr_type repr_type, unsigned int cnt)
38024a021edSSimon Horman {
38124a021edSSimon Horman u8 nfp_pcie = nfp_cppcore_pcie_unit(app->pf->cpp);
38224a021edSSimon Horman struct nfp_flower_priv *priv = app->priv;
383d2c2928dSDirk van der Merwe atomic_t *replies = &priv->reify_replies;
384b9452452SJohn Hurley struct nfp_flower_repr_priv *repr_priv;
38538edbf6fSJakub Kicinski enum nfp_port_type port_type;
386b9452452SJohn Hurley struct nfp_repr *nfp_repr;
38751ccc37dSDirk van der Merwe struct nfp_reprs *reprs;
388d2c2928dSDirk van der Merwe int i, err, reify_cnt;
38924a021edSSimon Horman const u8 queue = 0;
39024a021edSSimon Horman
39138edbf6fSJakub Kicinski port_type = repr_type == NFP_REPR_TYPE_PF ? NFP_PORT_PF_PORT :
39238edbf6fSJakub Kicinski NFP_PORT_VF_PORT;
39338edbf6fSJakub Kicinski
39424a021edSSimon Horman reprs = nfp_reprs_alloc(cnt);
39524a021edSSimon Horman if (!reprs)
39624a021edSSimon Horman return -ENOMEM;
39724a021edSSimon Horman
39824a021edSSimon Horman for (i = 0; i < cnt; i++) {
3993eb47dfcSJakub Kicinski struct net_device *repr;
40038edbf6fSJakub Kicinski struct nfp_port *port;
40124a021edSSimon Horman u32 port_id;
40224a021edSSimon Horman
4033eb47dfcSJakub Kicinski repr = nfp_repr_alloc(app);
4043eb47dfcSJakub Kicinski if (!repr) {
40524a021edSSimon Horman err = -ENOMEM;
40624a021edSSimon Horman goto err_reprs_clean;
40724a021edSSimon Horman }
40824a021edSSimon Horman
409b9452452SJohn Hurley repr_priv = kzalloc(sizeof(*repr_priv), GFP_KERNEL);
410b9452452SJohn Hurley if (!repr_priv) {
411b9452452SJohn Hurley err = -ENOMEM;
4128ce39eb5SNavid Emamdoost nfp_repr_free(repr);
413b9452452SJohn Hurley goto err_reprs_clean;
414b9452452SJohn Hurley }
415b9452452SJohn Hurley
416b9452452SJohn Hurley nfp_repr = netdev_priv(repr);
417b9452452SJohn Hurley nfp_repr->app_priv = repr_priv;
41820cce886SJohn Hurley repr_priv->nfp_repr = nfp_repr;
419b9452452SJohn Hurley
420ef0ec676SJakub Kicinski /* For now we only support 1 PF */
421ef0ec676SJakub Kicinski WARN_ON(repr_type == NFP_REPR_TYPE_PF && i);
422ef0ec676SJakub Kicinski
4233eb47dfcSJakub Kicinski port = nfp_port_alloc(app, port_type, repr);
4243b734ff6SJiri Pirko if (IS_ERR(port)) {
4253b734ff6SJiri Pirko err = PTR_ERR(port);
4268ce39eb5SNavid Emamdoost kfree(repr_priv);
4273b734ff6SJiri Pirko nfp_repr_free(repr);
4283b734ff6SJiri Pirko goto err_reprs_clean;
4293b734ff6SJiri Pirko }
43038edbf6fSJakub Kicinski if (repr_type == NFP_REPR_TYPE_PF) {
43138edbf6fSJakub Kicinski port->pf_id = i;
432ef0ec676SJakub Kicinski port->vnic = priv->nn->dp.ctrl_bar;
43338edbf6fSJakub Kicinski } else {
434ef0ec676SJakub Kicinski port->pf_id = 0;
43538edbf6fSJakub Kicinski port->vf_id = i;
436ef0ec676SJakub Kicinski port->vnic =
437ef0ec676SJakub Kicinski app->pf->vf_cfg_mem + i * NFP_NET_CFG_BAR_SZ;
43838edbf6fSJakub Kicinski }
43938edbf6fSJakub Kicinski
4403eb47dfcSJakub Kicinski eth_hw_addr_random(repr);
44124a021edSSimon Horman
44224a021edSSimon Horman port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type,
44324a021edSSimon Horman i, queue);
4443eb47dfcSJakub Kicinski err = nfp_repr_init(app, repr,
44538edbf6fSJakub Kicinski port_id, port, priv->nn->dp.netdev);
44638edbf6fSJakub Kicinski if (err) {
4478ce39eb5SNavid Emamdoost kfree(repr_priv);
44838edbf6fSJakub Kicinski nfp_port_free(port);
4493b734ff6SJiri Pirko nfp_repr_free(repr);
45024a021edSSimon Horman goto err_reprs_clean;
45138edbf6fSJakub Kicinski }
45224a021edSSimon Horman
4533b734ff6SJiri Pirko RCU_INIT_POINTER(reprs->reprs[i], repr);
45424a021edSSimon Horman nfp_info(app->cpp, "%s%d Representor(%s) created\n",
45524a021edSSimon Horman repr_type == NFP_REPR_TYPE_PF ? "PF" : "VF", i,
4563eb47dfcSJakub Kicinski repr->name);
45724a021edSSimon Horman }
45824a021edSSimon Horman
45951ccc37dSDirk van der Merwe nfp_app_reprs_set(app, repr_type, reprs);
46024a021edSSimon Horman
461d2c2928dSDirk van der Merwe atomic_set(replies, 0);
462d2c2928dSDirk van der Merwe reify_cnt = nfp_flower_reprs_reify(app, repr_type, true);
463d2c2928dSDirk van der Merwe if (reify_cnt < 0) {
464d2c2928dSDirk van der Merwe err = reify_cnt;
465d2c2928dSDirk van der Merwe nfp_warn(app->cpp, "Failed to notify firmware about repr creation\n");
466d2c2928dSDirk van der Merwe goto err_reprs_remove;
467d2c2928dSDirk van der Merwe }
468d2c2928dSDirk van der Merwe
469d2c2928dSDirk van der Merwe err = nfp_flower_wait_repr_reify(app, replies, reify_cnt);
470d2c2928dSDirk van der Merwe if (err)
471d2c2928dSDirk van der Merwe goto err_reprs_remove;
472d2c2928dSDirk van der Merwe
47324a021edSSimon Horman return 0;
474d2c2928dSDirk van der Merwe err_reprs_remove:
475d2c2928dSDirk van der Merwe reprs = nfp_app_reprs_set(app, repr_type, NULL);
47624a021edSSimon Horman err_reprs_clean:
4773eb47dfcSJakub Kicinski nfp_reprs_clean_and_free(app, reprs);
47824a021edSSimon Horman return err;
47924a021edSSimon Horman }
48024a021edSSimon Horman
nfp_flower_sriov_enable(struct nfp_app * app,int num_vfs)48124a021edSSimon Horman static int nfp_flower_sriov_enable(struct nfp_app *app, int num_vfs)
48224a021edSSimon Horman {
483192e6851SJakub Kicinski struct nfp_flower_priv *priv = app->priv;
484192e6851SJakub Kicinski
485192e6851SJakub Kicinski if (!priv->nn)
486192e6851SJakub Kicinski return 0;
487192e6851SJakub Kicinski
48824a021edSSimon Horman return nfp_flower_spawn_vnic_reprs(app,
48924a021edSSimon Horman NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF,
49024a021edSSimon Horman NFP_REPR_TYPE_VF, num_vfs);
49124a021edSSimon Horman }
49224a021edSSimon Horman
49324a021edSSimon Horman static int
nfp_flower_spawn_phy_reprs(struct nfp_app * app,struct nfp_flower_priv * priv)49424a021edSSimon Horman nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
4951025351aSSimon Horman {
4961025351aSSimon Horman struct nfp_eth_table *eth_tbl = app->pf->eth_tbl;
497d2c2928dSDirk van der Merwe atomic_t *replies = &priv->reify_replies;
498b9452452SJohn Hurley struct nfp_flower_repr_priv *repr_priv;
499b9452452SJohn Hurley struct nfp_repr *nfp_repr;
50012acb133SSimon Horman struct sk_buff *ctrl_skb;
50151ccc37dSDirk van der Merwe struct nfp_reprs *reprs;
502d2c2928dSDirk van der Merwe int err, reify_cnt;
5031025351aSSimon Horman unsigned int i;
5041025351aSSimon Horman
50512acb133SSimon Horman ctrl_skb = nfp_flower_cmsg_mac_repr_start(app, eth_tbl->count);
50612acb133SSimon Horman if (!ctrl_skb)
5071025351aSSimon Horman return -ENOMEM;
5081025351aSSimon Horman
50912acb133SSimon Horman reprs = nfp_reprs_alloc(eth_tbl->max_index + 1);
51012acb133SSimon Horman if (!reprs) {
51112acb133SSimon Horman err = -ENOMEM;
51212acb133SSimon Horman goto err_free_ctrl_skb;
51312acb133SSimon Horman }
51412acb133SSimon Horman
5151025351aSSimon Horman for (i = 0; i < eth_tbl->count; i++) {
51612acb133SSimon Horman unsigned int phys_port = eth_tbl->ports[i].index;
5173eb47dfcSJakub Kicinski struct net_device *repr;
5181025351aSSimon Horman struct nfp_port *port;
5191025351aSSimon Horman u32 cmsg_port_id;
5201025351aSSimon Horman
5213eb47dfcSJakub Kicinski repr = nfp_repr_alloc(app);
5223eb47dfcSJakub Kicinski if (!repr) {
5231025351aSSimon Horman err = -ENOMEM;
5241025351aSSimon Horman goto err_reprs_clean;
5251025351aSSimon Horman }
5261025351aSSimon Horman
527b9452452SJohn Hurley repr_priv = kzalloc(sizeof(*repr_priv), GFP_KERNEL);
528b9452452SJohn Hurley if (!repr_priv) {
529b9452452SJohn Hurley err = -ENOMEM;
5308572cea1SNavid Emamdoost nfp_repr_free(repr);
531b9452452SJohn Hurley goto err_reprs_clean;
532b9452452SJohn Hurley }
533b9452452SJohn Hurley
534b9452452SJohn Hurley nfp_repr = netdev_priv(repr);
535b9452452SJohn Hurley nfp_repr->app_priv = repr_priv;
53620cce886SJohn Hurley repr_priv->nfp_repr = nfp_repr;
537b9452452SJohn Hurley
5383eb47dfcSJakub Kicinski port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, repr);
5391025351aSSimon Horman if (IS_ERR(port)) {
5401025351aSSimon Horman err = PTR_ERR(port);
5418572cea1SNavid Emamdoost kfree(repr_priv);
5423b734ff6SJiri Pirko nfp_repr_free(repr);
5431025351aSSimon Horman goto err_reprs_clean;
5441025351aSSimon Horman }
5451025351aSSimon Horman err = nfp_port_init_phy_port(app->pf, app, port, i);
5461025351aSSimon Horman if (err) {
5478572cea1SNavid Emamdoost kfree(repr_priv);
5481025351aSSimon Horman nfp_port_free(port);
5493b734ff6SJiri Pirko nfp_repr_free(repr);
5501025351aSSimon Horman goto err_reprs_clean;
5511025351aSSimon Horman }
5521025351aSSimon Horman
5533eb47dfcSJakub Kicinski SET_NETDEV_DEV(repr, &priv->nn->pdev->dev);
554c55ca688SJakub Kicinski nfp_net_get_mac_addr(app->pf, repr, port);
5551025351aSSimon Horman
5561025351aSSimon Horman cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port);
5573eb47dfcSJakub Kicinski err = nfp_repr_init(app, repr,
5581025351aSSimon Horman cmsg_port_id, port, priv->nn->dp.netdev);
5591025351aSSimon Horman if (err) {
5608572cea1SNavid Emamdoost kfree(repr_priv);
5611025351aSSimon Horman nfp_port_free(port);
5623b734ff6SJiri Pirko nfp_repr_free(repr);
5631025351aSSimon Horman goto err_reprs_clean;
5641025351aSSimon Horman }
5651025351aSSimon Horman
56612acb133SSimon Horman nfp_flower_cmsg_mac_repr_add(ctrl_skb, i,
56712acb133SSimon Horman eth_tbl->ports[i].nbi,
56812acb133SSimon Horman eth_tbl->ports[i].base,
56912acb133SSimon Horman phys_port);
57012acb133SSimon Horman
5713b734ff6SJiri Pirko RCU_INIT_POINTER(reprs->reprs[phys_port], repr);
5721025351aSSimon Horman nfp_info(app->cpp, "Phys Port %d Representor(%s) created\n",
5733eb47dfcSJakub Kicinski phys_port, repr->name);
5741025351aSSimon Horman }
5751025351aSSimon Horman
57651ccc37dSDirk van der Merwe nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs);
5771025351aSSimon Horman
578d2c2928dSDirk van der Merwe /* The REIFY/MAC_REPR control messages should be sent after the MAC
57912acb133SSimon Horman * representors are registered using nfp_app_reprs_set(). This is
58012acb133SSimon Horman * because the firmware may respond with control messages for the
58112acb133SSimon Horman * MAC representors, f.e. to provide the driver with information
58212acb133SSimon Horman * about their state, and without registration the driver will drop
58312acb133SSimon Horman * any such messages.
58412acb133SSimon Horman */
585d2c2928dSDirk van der Merwe atomic_set(replies, 0);
586d2c2928dSDirk van der Merwe reify_cnt = nfp_flower_reprs_reify(app, NFP_REPR_TYPE_PHYS_PORT, true);
587d2c2928dSDirk van der Merwe if (reify_cnt < 0) {
588d2c2928dSDirk van der Merwe err = reify_cnt;
589d2c2928dSDirk van der Merwe nfp_warn(app->cpp, "Failed to notify firmware about repr creation\n");
590d2c2928dSDirk van der Merwe goto err_reprs_remove;
591d2c2928dSDirk van der Merwe }
592d2c2928dSDirk van der Merwe
593d2c2928dSDirk van der Merwe err = nfp_flower_wait_repr_reify(app, replies, reify_cnt);
594d2c2928dSDirk van der Merwe if (err)
595d2c2928dSDirk van der Merwe goto err_reprs_remove;
596d2c2928dSDirk van der Merwe
59712acb133SSimon Horman nfp_ctrl_tx(app->ctrl, ctrl_skb);
59812acb133SSimon Horman
5991025351aSSimon Horman return 0;
600d2c2928dSDirk van der Merwe err_reprs_remove:
601d2c2928dSDirk van der Merwe reprs = nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, NULL);
6021025351aSSimon Horman err_reprs_clean:
6033eb47dfcSJakub Kicinski nfp_reprs_clean_and_free(app, reprs);
60412acb133SSimon Horman err_free_ctrl_skb:
60512acb133SSimon Horman kfree_skb(ctrl_skb);
6061025351aSSimon Horman return err;
6071025351aSSimon Horman }
6081025351aSSimon Horman
nfp_flower_vnic_alloc(struct nfp_app * app,struct nfp_net * nn,unsigned int id)609c496291cSJakub Kicinski static int nfp_flower_vnic_alloc(struct nfp_app *app, struct nfp_net *nn,
6101025351aSSimon Horman unsigned int id)
6111025351aSSimon Horman {
6121025351aSSimon Horman if (id > 0) {
6131025351aSSimon Horman nfp_warn(app->cpp, "FlowerNIC doesn't support more than one data vNIC\n");
6141025351aSSimon Horman goto err_invalid_port;
6151025351aSSimon Horman }
6161025351aSSimon Horman
6171025351aSSimon Horman eth_hw_addr_random(nn->dp.netdev);
6181025351aSSimon Horman netif_keep_dst(nn->dp.netdev);
619fe06a64eSJakub Kicinski nn->vnic_no_name = true;
6201025351aSSimon Horman
6211025351aSSimon Horman return 0;
6221025351aSSimon Horman
6231025351aSSimon Horman err_invalid_port:
6241025351aSSimon Horman nn->port = nfp_port_alloc(app, NFP_PORT_INVALID, nn->dp.netdev);
6251025351aSSimon Horman return PTR_ERR_OR_ZERO(nn->port);
6261025351aSSimon Horman }
6271025351aSSimon Horman
nfp_flower_vnic_clean(struct nfp_app * app,struct nfp_net * nn)628c496291cSJakub Kicinski static void nfp_flower_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
629c496291cSJakub Kicinski {
630c496291cSJakub Kicinski struct nfp_flower_priv *priv = app->priv;
631c496291cSJakub Kicinski
632192e6851SJakub Kicinski if (app->pf->num_vfs)
633192e6851SJakub Kicinski nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF);
634192e6851SJakub Kicinski nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
635192e6851SJakub Kicinski nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
636192e6851SJakub Kicinski
637c496291cSJakub Kicinski priv->nn = NULL;
638c496291cSJakub Kicinski }
639c496291cSJakub Kicinski
nfp_flower_vnic_init(struct nfp_app * app,struct nfp_net * nn)640c496291cSJakub Kicinski static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn)
641c496291cSJakub Kicinski {
642c496291cSJakub Kicinski struct nfp_flower_priv *priv = app->priv;
643192e6851SJakub Kicinski int err;
644c496291cSJakub Kicinski
645c496291cSJakub Kicinski priv->nn = nn;
646c496291cSJakub Kicinski
647192e6851SJakub Kicinski err = nfp_flower_spawn_phy_reprs(app, app->priv);
648192e6851SJakub Kicinski if (err)
649192e6851SJakub Kicinski goto err_clear_nn;
650192e6851SJakub Kicinski
651192e6851SJakub Kicinski err = nfp_flower_spawn_vnic_reprs(app,
652192e6851SJakub Kicinski NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF,
653192e6851SJakub Kicinski NFP_REPR_TYPE_PF, 1);
654192e6851SJakub Kicinski if (err)
655192e6851SJakub Kicinski goto err_destroy_reprs_phy;
656192e6851SJakub Kicinski
657192e6851SJakub Kicinski if (app->pf->num_vfs) {
658192e6851SJakub Kicinski err = nfp_flower_spawn_vnic_reprs(app,
659192e6851SJakub Kicinski NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF,
660192e6851SJakub Kicinski NFP_REPR_TYPE_VF,
661192e6851SJakub Kicinski app->pf->num_vfs);
662192e6851SJakub Kicinski if (err)
663192e6851SJakub Kicinski goto err_destroy_reprs_pf;
664192e6851SJakub Kicinski }
665192e6851SJakub Kicinski
666c496291cSJakub Kicinski return 0;
667192e6851SJakub Kicinski
668192e6851SJakub Kicinski err_destroy_reprs_pf:
669192e6851SJakub Kicinski nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
670192e6851SJakub Kicinski err_destroy_reprs_phy:
671192e6851SJakub Kicinski nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
672192e6851SJakub Kicinski err_clear_nn:
673192e6851SJakub Kicinski priv->nn = NULL;
674192e6851SJakub Kicinski return err;
675c496291cSJakub Kicinski }
676c496291cSJakub Kicinski
nfp_flower_wait_host_bit(struct nfp_app * app)677465957c2SLouis Peens static void nfp_flower_wait_host_bit(struct nfp_app *app)
678465957c2SLouis Peens {
679465957c2SLouis Peens unsigned long err_at;
680465957c2SLouis Peens u64 feat;
681465957c2SLouis Peens int err;
682465957c2SLouis Peens
683465957c2SLouis Peens /* Wait for HOST_ACK flag bit to propagate */
684465957c2SLouis Peens err_at = jiffies + msecs_to_jiffies(100);
685465957c2SLouis Peens do {
686465957c2SLouis Peens feat = nfp_rtsym_read_le(app->pf->rtbl,
687465957c2SLouis Peens "_abi_flower_combined_features_global",
688465957c2SLouis Peens &err);
689465957c2SLouis Peens if (time_is_before_eq_jiffies(err_at)) {
690465957c2SLouis Peens nfp_warn(app->cpp,
691465957c2SLouis Peens "HOST_ACK bit not propagated in FW.\n");
692465957c2SLouis Peens break;
693465957c2SLouis Peens }
694465957c2SLouis Peens usleep_range(1000, 2000);
695465957c2SLouis Peens } while (!err && !(feat & NFP_FL_FEATS_HOST_ACK));
696465957c2SLouis Peens
697465957c2SLouis Peens if (err)
698465957c2SLouis Peens nfp_warn(app->cpp,
699465957c2SLouis Peens "Could not read global features entry from FW\n");
700465957c2SLouis Peens }
701465957c2SLouis Peens
nfp_flower_sync_feature_bits(struct nfp_app * app)702465957c2SLouis Peens static int nfp_flower_sync_feature_bits(struct nfp_app *app)
703465957c2SLouis Peens {
704465957c2SLouis Peens struct nfp_flower_priv *app_priv = app->priv;
705465957c2SLouis Peens int err;
706465957c2SLouis Peens
707465957c2SLouis Peens /* Tell the firmware of the host supported features. */
708465957c2SLouis Peens err = nfp_rtsym_write_le(app->pf->rtbl, "_abi_flower_host_mask",
709465957c2SLouis Peens app_priv->flower_ext_feats |
710465957c2SLouis Peens NFP_FL_FEATS_HOST_ACK);
711465957c2SLouis Peens if (!err)
712465957c2SLouis Peens nfp_flower_wait_host_bit(app);
713465957c2SLouis Peens else if (err != -ENOENT)
714465957c2SLouis Peens return err;
715465957c2SLouis Peens
716465957c2SLouis Peens /* Tell the firmware that the driver supports lag. */
717465957c2SLouis Peens err = nfp_rtsym_write_le(app->pf->rtbl,
718465957c2SLouis Peens "_abi_flower_balance_sync_enable", 1);
719465957c2SLouis Peens if (!err) {
720f0b37fa6SLouis Peens app_priv->flower_en_feats |= NFP_FL_ENABLE_LAG;
721465957c2SLouis Peens nfp_flower_lag_init(&app_priv->nfp_lag);
722465957c2SLouis Peens } else if (err == -ENOENT) {
723465957c2SLouis Peens nfp_warn(app->cpp, "LAG not supported by FW.\n");
724465957c2SLouis Peens } else {
725465957c2SLouis Peens return err;
726465957c2SLouis Peens }
727465957c2SLouis Peens
728465957c2SLouis Peens if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MOD) {
729465957c2SLouis Peens /* Tell the firmware that the driver supports flow merging. */
730465957c2SLouis Peens err = nfp_rtsym_write_le(app->pf->rtbl,
731465957c2SLouis Peens "_abi_flower_merge_hint_enable", 1);
732465957c2SLouis Peens if (!err) {
733f0b37fa6SLouis Peens app_priv->flower_en_feats |= NFP_FL_ENABLE_FLOW_MERGE;
734465957c2SLouis Peens nfp_flower_internal_port_init(app_priv);
735465957c2SLouis Peens } else if (err == -ENOENT) {
736465957c2SLouis Peens nfp_warn(app->cpp,
737465957c2SLouis Peens "Flow merge not supported by FW.\n");
738465957c2SLouis Peens } else {
739465957c2SLouis Peens return err;
740465957c2SLouis Peens }
741465957c2SLouis Peens } else {
742465957c2SLouis Peens nfp_warn(app->cpp, "Flow mod/merge not supported by FW.\n");
743465957c2SLouis Peens }
744465957c2SLouis Peens
745465957c2SLouis Peens return 0;
746465957c2SLouis Peens }
747465957c2SLouis Peens
nfp_flower_init(struct nfp_app * app)7481025351aSSimon Horman static int nfp_flower_init(struct nfp_app *app)
7491025351aSSimon Horman {
750467322e2SPieter Jansen van Vuuren u64 version, features, ctx_count, num_mems;
7511025351aSSimon Horman const struct nfp_pf *pf = app->pf;
752b985f870SSimon Horman struct nfp_flower_priv *app_priv;
7538a276873SPieter Jansen van Vuuren int err;
7541025351aSSimon Horman
7551025351aSSimon Horman if (!pf->eth_tbl) {
7561025351aSSimon Horman nfp_warn(app->cpp, "FlowerNIC requires eth table\n");
7571025351aSSimon Horman return -EINVAL;
7581025351aSSimon Horman }
7591025351aSSimon Horman
7601025351aSSimon Horman if (!pf->mac_stats_bar) {
7611025351aSSimon Horman nfp_warn(app->cpp, "FlowerNIC requires mac_stats BAR\n");
7621025351aSSimon Horman return -EINVAL;
7631025351aSSimon Horman }
7641025351aSSimon Horman
7651025351aSSimon Horman if (!pf->vf_cfg_bar) {
7661025351aSSimon Horman nfp_warn(app->cpp, "FlowerNIC requires vf_cfg BAR\n");
7671025351aSSimon Horman return -EINVAL;
7681025351aSSimon Horman }
7691025351aSSimon Horman
7708a276873SPieter Jansen van Vuuren version = nfp_rtsym_read_le(app->pf->rtbl, "hw_flower_version", &err);
7718a276873SPieter Jansen van Vuuren if (err) {
7728a276873SPieter Jansen van Vuuren nfp_warn(app->cpp, "FlowerNIC requires hw_flower_version memory symbol\n");
7738a276873SPieter Jansen van Vuuren return err;
7748a276873SPieter Jansen van Vuuren }
7758a276873SPieter Jansen van Vuuren
776467322e2SPieter Jansen van Vuuren num_mems = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_SPLIT",
777467322e2SPieter Jansen van Vuuren &err);
778467322e2SPieter Jansen van Vuuren if (err) {
779467322e2SPieter Jansen van Vuuren nfp_warn(app->cpp,
780467322e2SPieter Jansen van Vuuren "FlowerNIC: unsupported host context memory: %d\n",
781467322e2SPieter Jansen van Vuuren err);
782467322e2SPieter Jansen van Vuuren err = 0;
783467322e2SPieter Jansen van Vuuren num_mems = 1;
784467322e2SPieter Jansen van Vuuren }
785467322e2SPieter Jansen van Vuuren
786467322e2SPieter Jansen van Vuuren if (!FIELD_FIT(NFP_FL_STAT_ID_MU_NUM, num_mems) || !num_mems) {
787467322e2SPieter Jansen van Vuuren nfp_warn(app->cpp,
788467322e2SPieter Jansen van Vuuren "FlowerNIC: invalid host context memory: %llu\n",
789467322e2SPieter Jansen van Vuuren num_mems);
790467322e2SPieter Jansen van Vuuren return -EINVAL;
791467322e2SPieter Jansen van Vuuren }
792467322e2SPieter Jansen van Vuuren
79312ecf615SPieter Jansen van Vuuren ctx_count = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_COUNT",
79412ecf615SPieter Jansen van Vuuren &err);
79512ecf615SPieter Jansen van Vuuren if (err) {
79612ecf615SPieter Jansen van Vuuren nfp_warn(app->cpp,
79712ecf615SPieter Jansen van Vuuren "FlowerNIC: unsupported host context count: %d\n",
79812ecf615SPieter Jansen van Vuuren err);
79912ecf615SPieter Jansen van Vuuren err = 0;
80012ecf615SPieter Jansen van Vuuren ctx_count = BIT(17);
80112ecf615SPieter Jansen van Vuuren }
80212ecf615SPieter Jansen van Vuuren
8038a276873SPieter Jansen van Vuuren /* We need to ensure hardware has enough flower capabilities. */
8048a276873SPieter Jansen van Vuuren if (version != NFP_FLOWER_ALLOWED_VER) {
8058a276873SPieter Jansen van Vuuren nfp_warn(app->cpp, "FlowerNIC: unsupported firmware version\n");
8068a276873SPieter Jansen van Vuuren return -EINVAL;
8078a276873SPieter Jansen van Vuuren }
8088a276873SPieter Jansen van Vuuren
809b985f870SSimon Horman app_priv = vzalloc(sizeof(struct nfp_flower_priv));
810b985f870SSimon Horman if (!app_priv)
8119ce6bbbbSJakub Kicinski return -ENOMEM;
8129ce6bbbbSJakub Kicinski
813467322e2SPieter Jansen van Vuuren app_priv->total_mem_units = num_mems;
814467322e2SPieter Jansen van Vuuren app_priv->active_mem_unit = 0;
81512ecf615SPieter Jansen van Vuuren app_priv->stats_ring_size = roundup_pow_of_two(ctx_count);
816b985f870SSimon Horman app->priv = app_priv;
817c496291cSJakub Kicinski app_priv->app = app;
818cf2cbadcSPieter Jansen van Vuuren skb_queue_head_init(&app_priv->cmsg_skbs_high);
819cf2cbadcSPieter Jansen van Vuuren skb_queue_head_init(&app_priv->cmsg_skbs_low);
820b985f870SSimon Horman INIT_WORK(&app_priv->cmsg_work, nfp_flower_cmsg_process_rx);
821d2c2928dSDirk van der Merwe init_waitqueue_head(&app_priv->reify_wait_queue);
822b985f870SSimon Horman
82329a5dcaeSJohn Hurley init_waitqueue_head(&app_priv->mtu_conf.wait_q);
82429a5dcaeSJohn Hurley spin_lock_init(&app_priv->mtu_conf.lock);
82529a5dcaeSJohn Hurley
826467322e2SPieter Jansen van Vuuren err = nfp_flower_metadata_init(app, ctx_count, num_mems);
82743f84b72SPieter Jansen van Vuuren if (err)
82843f84b72SPieter Jansen van Vuuren goto err_free_app_priv;
82943f84b72SPieter Jansen van Vuuren
83073997348SJohn Hurley /* Extract the extra features supported by the firmware. */
83173997348SJohn Hurley features = nfp_rtsym_read_le(app->pf->rtbl,
83273997348SJohn Hurley "_abi_flower_extra_features", &err);
83373997348SJohn Hurley if (err)
83473997348SJohn Hurley app_priv->flower_ext_feats = 0;
83573997348SJohn Hurley else
836465957c2SLouis Peens app_priv->flower_ext_feats = features & NFP_FL_FEATS_HOST;
83773997348SJohn Hurley
838465957c2SLouis Peens err = nfp_flower_sync_feature_bits(app);
839465957c2SLouis Peens if (err)
840465957c2SLouis Peens goto err_cleanup;
8412f2622f5SJohn Hurley
8425fb5c395SPieter Jansen van Vuuren if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM)
8435fb5c395SPieter Jansen van Vuuren nfp_flower_qos_init(app);
8445fb5c395SPieter Jansen van Vuuren
8453166dd07SJohn Hurley INIT_LIST_HEAD(&app_priv->indr_block_cb_priv);
84605d2bee6SJohn Hurley INIT_LIST_HEAD(&app_priv->non_repr_priv);
847f12725d9SJohn Hurley app_priv->pre_tun_rule_cnt = 0;
8483166dd07SJohn Hurley
8491025351aSSimon Horman return 0;
85043f84b72SPieter Jansen van Vuuren
851465957c2SLouis Peens err_cleanup:
852f0b37fa6SLouis Peens if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG)
8532f2622f5SJohn Hurley nfp_flower_lag_cleanup(&app_priv->nfp_lag);
854898bc7d6SJohn Hurley nfp_flower_metadata_cleanup(app);
85543f84b72SPieter Jansen van Vuuren err_free_app_priv:
85643f84b72SPieter Jansen van Vuuren vfree(app->priv);
85743f84b72SPieter Jansen van Vuuren return err;
8581025351aSSimon Horman }
8591025351aSSimon Horman
nfp_flower_clean(struct nfp_app * app)8609ce6bbbbSJakub Kicinski static void nfp_flower_clean(struct nfp_app *app)
8619ce6bbbbSJakub Kicinski {
862b985f870SSimon Horman struct nfp_flower_priv *app_priv = app->priv;
863b985f870SSimon Horman
864cf2cbadcSPieter Jansen van Vuuren skb_queue_purge(&app_priv->cmsg_skbs_high);
865cf2cbadcSPieter Jansen van Vuuren skb_queue_purge(&app_priv->cmsg_skbs_low);
866b985f870SSimon Horman flush_work(&app_priv->cmsg_work);
867b985f870SSimon Horman
8685fb5c395SPieter Jansen van Vuuren if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM)
8695fb5c395SPieter Jansen van Vuuren nfp_flower_qos_cleanup(app);
8705fb5c395SPieter Jansen van Vuuren
871e09303d3SLouis Peens if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG)
872bb9a8d03SJohn Hurley nfp_flower_lag_cleanup(&app_priv->nfp_lag);
873bb9a8d03SJohn Hurley
874e09303d3SLouis Peens if (app_priv->flower_en_feats & NFP_FL_ENABLE_FLOW_MERGE)
8754d12ba42SJohn Hurley nfp_flower_internal_port_cleanup(app_priv);
8764d12ba42SJohn Hurley
877df7c7dd2SJakub Kicinski nfp_flower_metadata_cleanup(app);
87843f84b72SPieter Jansen van Vuuren vfree(app->priv);
8799ce6bbbbSJakub Kicinski app->priv = NULL;
8809ce6bbbbSJakub Kicinski }
8819ce6bbbbSJakub Kicinski
nfp_flower_check_ack(struct nfp_flower_priv * app_priv)88229a5dcaeSJohn Hurley static bool nfp_flower_check_ack(struct nfp_flower_priv *app_priv)
88329a5dcaeSJohn Hurley {
88429a5dcaeSJohn Hurley bool ret;
88529a5dcaeSJohn Hurley
88629a5dcaeSJohn Hurley spin_lock_bh(&app_priv->mtu_conf.lock);
88729a5dcaeSJohn Hurley ret = app_priv->mtu_conf.ack;
88829a5dcaeSJohn Hurley spin_unlock_bh(&app_priv->mtu_conf.lock);
88929a5dcaeSJohn Hurley
89029a5dcaeSJohn Hurley return ret;
89129a5dcaeSJohn Hurley }
89229a5dcaeSJohn Hurley
89329a5dcaeSJohn Hurley static int
nfp_flower_repr_change_mtu(struct nfp_app * app,struct net_device * netdev,int new_mtu)89429a5dcaeSJohn Hurley nfp_flower_repr_change_mtu(struct nfp_app *app, struct net_device *netdev,
89529a5dcaeSJohn Hurley int new_mtu)
89629a5dcaeSJohn Hurley {
89729a5dcaeSJohn Hurley struct nfp_flower_priv *app_priv = app->priv;
89829a5dcaeSJohn Hurley struct nfp_repr *repr = netdev_priv(netdev);
89996439889SFred Lotter int err;
90029a5dcaeSJohn Hurley
90129a5dcaeSJohn Hurley /* Only need to config FW for physical port MTU change. */
90229a5dcaeSJohn Hurley if (repr->port->type != NFP_PORT_PHYS_PORT)
90329a5dcaeSJohn Hurley return 0;
90429a5dcaeSJohn Hurley
90529a5dcaeSJohn Hurley if (!(app_priv->flower_ext_feats & NFP_FL_NBI_MTU_SETTING)) {
90629a5dcaeSJohn Hurley nfp_err(app->cpp, "Physical port MTU setting not supported\n");
90729a5dcaeSJohn Hurley return -EINVAL;
90829a5dcaeSJohn Hurley }
90929a5dcaeSJohn Hurley
91029a5dcaeSJohn Hurley spin_lock_bh(&app_priv->mtu_conf.lock);
91129a5dcaeSJohn Hurley app_priv->mtu_conf.ack = false;
91229a5dcaeSJohn Hurley app_priv->mtu_conf.requested_val = new_mtu;
91329a5dcaeSJohn Hurley app_priv->mtu_conf.portnum = repr->dst->u.port_info.port_id;
91429a5dcaeSJohn Hurley spin_unlock_bh(&app_priv->mtu_conf.lock);
91529a5dcaeSJohn Hurley
91629a5dcaeSJohn Hurley err = nfp_flower_cmsg_portmod(repr, netif_carrier_ok(netdev), new_mtu,
91729a5dcaeSJohn Hurley true);
91829a5dcaeSJohn Hurley if (err) {
91929a5dcaeSJohn Hurley spin_lock_bh(&app_priv->mtu_conf.lock);
92029a5dcaeSJohn Hurley app_priv->mtu_conf.requested_val = 0;
92129a5dcaeSJohn Hurley spin_unlock_bh(&app_priv->mtu_conf.lock);
92229a5dcaeSJohn Hurley return err;
92329a5dcaeSJohn Hurley }
92429a5dcaeSJohn Hurley
92529a5dcaeSJohn Hurley /* Wait for fw to ack the change. */
92696439889SFred Lotter if (!wait_event_timeout(app_priv->mtu_conf.wait_q,
92729a5dcaeSJohn Hurley nfp_flower_check_ack(app_priv),
92896439889SFred Lotter NFP_FL_REPLY_TIMEOUT)) {
92929a5dcaeSJohn Hurley spin_lock_bh(&app_priv->mtu_conf.lock);
93029a5dcaeSJohn Hurley app_priv->mtu_conf.requested_val = 0;
93129a5dcaeSJohn Hurley spin_unlock_bh(&app_priv->mtu_conf.lock);
93229a5dcaeSJohn Hurley nfp_warn(app->cpp, "MTU change not verified with fw\n");
93329a5dcaeSJohn Hurley return -EIO;
93429a5dcaeSJohn Hurley }
93529a5dcaeSJohn Hurley
93629a5dcaeSJohn Hurley return 0;
93729a5dcaeSJohn Hurley }
93829a5dcaeSJohn Hurley
nfp_flower_start(struct nfp_app * app)939fd0dd1abSJohn Hurley static int nfp_flower_start(struct nfp_app *app)
940fd0dd1abSJohn Hurley {
941bb9a8d03SJohn Hurley struct nfp_flower_priv *app_priv = app->priv;
942bb9a8d03SJohn Hurley int err;
943bb9a8d03SJohn Hurley
944e09303d3SLouis Peens if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) {
945bb9a8d03SJohn Hurley err = nfp_flower_lag_reset(&app_priv->nfp_lag);
946bb9a8d03SJohn Hurley if (err)
947bb9a8d03SJohn Hurley return err;
948bb9a8d03SJohn Hurley }
949bb9a8d03SJohn Hurley
95060d950f4SBaowen Zheng err = flow_indr_dev_register(nfp_flower_indr_setup_tc_cb, app);
95160d950f4SBaowen Zheng if (err)
95260d950f4SBaowen Zheng return err;
95360d950f4SBaowen Zheng
95460d950f4SBaowen Zheng err = nfp_tunnel_config_start(app);
95560d950f4SBaowen Zheng if (err)
95660d950f4SBaowen Zheng goto err_tunnel_config;
95760d950f4SBaowen Zheng
95860d950f4SBaowen Zheng return 0;
95960d950f4SBaowen Zheng
96060d950f4SBaowen Zheng err_tunnel_config:
96160d950f4SBaowen Zheng flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app,
96260d950f4SBaowen Zheng nfp_flower_setup_indr_tc_release);
96360d950f4SBaowen Zheng return err;
964fd0dd1abSJohn Hurley }
965fd0dd1abSJohn Hurley
nfp_flower_stop(struct nfp_app * app)966fd0dd1abSJohn Hurley static void nfp_flower_stop(struct nfp_app *app)
967fd0dd1abSJohn Hurley {
968fd0dd1abSJohn Hurley nfp_tunnel_config_stop(app);
9695b33afeeSSimon Horman
9705b33afeeSSimon Horman flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app,
9715b33afeeSSimon Horman nfp_flower_setup_indr_tc_release);
972fd0dd1abSJohn Hurley }
973fd0dd1abSJohn Hurley
9740c665e2bSJakub Kicinski static int
nfp_flower_netdev_event(struct nfp_app * app,struct net_device * netdev,unsigned long event,void * ptr)9750c665e2bSJakub Kicinski nfp_flower_netdev_event(struct nfp_app *app, struct net_device *netdev,
9760c665e2bSJakub Kicinski unsigned long event, void *ptr)
9770c665e2bSJakub Kicinski {
9780c665e2bSJakub Kicinski struct nfp_flower_priv *app_priv = app->priv;
9790c665e2bSJakub Kicinski int ret;
9800c665e2bSJakub Kicinski
981e09303d3SLouis Peens if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) {
9820c665e2bSJakub Kicinski ret = nfp_flower_lag_netdev_event(app_priv, netdev, event, ptr);
9830c665e2bSJakub Kicinski if (ret & NOTIFY_STOP_MASK)
9840c665e2bSJakub Kicinski return ret;
9850c665e2bSJakub Kicinski }
9860c665e2bSJakub Kicinski
9874d12ba42SJohn Hurley ret = nfp_flower_internal_port_event_handler(app, netdev, event);
9884d12ba42SJohn Hurley if (ret & NOTIFY_STOP_MASK)
9894d12ba42SJohn Hurley return ret;
9904d12ba42SJohn Hurley
9910c665e2bSJakub Kicinski return nfp_tunnel_mac_event_handler(app, netdev, event, ptr);
9920c665e2bSJakub Kicinski }
9930c665e2bSJakub Kicinski
9941025351aSSimon Horman const struct nfp_app_type app_flower = {
9951025351aSSimon Horman .id = NFP_APP_FLOWER_NIC,
9961025351aSSimon Horman .name = "flower",
99778a0a65fSJakub Kicinski
99878a0a65fSJakub Kicinski .ctrl_cap_mask = ~0U,
9991025351aSSimon Horman .ctrl_has_meta = true,
10001025351aSSimon Horman
10011025351aSSimon Horman .extra_cap = nfp_flower_extra_cap,
10021025351aSSimon Horman
10031025351aSSimon Horman .init = nfp_flower_init,
10049ce6bbbbSJakub Kicinski .clean = nfp_flower_clean,
10051025351aSSimon Horman
100629a5dcaeSJohn Hurley .repr_change_mtu = nfp_flower_repr_change_mtu,
100729a5dcaeSJohn Hurley
1008c496291cSJakub Kicinski .vnic_alloc = nfp_flower_vnic_alloc,
10091025351aSSimon Horman .vnic_init = nfp_flower_vnic_init,
1010c496291cSJakub Kicinski .vnic_clean = nfp_flower_vnic_clean,
10111025351aSSimon Horman
1012d2c2928dSDirk van der Merwe .repr_preclean = nfp_flower_repr_netdev_preclean,
10131a24d4f9SJohn Hurley .repr_clean = nfp_flower_repr_netdev_clean,
10141a24d4f9SJohn Hurley
10155d7c64a7SJakub Kicinski .repr_open = nfp_flower_repr_netdev_open,
10165d7c64a7SJakub Kicinski .repr_stop = nfp_flower_repr_netdev_stop,
10175d7c64a7SJakub Kicinski
1018fd0dd1abSJohn Hurley .start = nfp_flower_start,
1019fd0dd1abSJohn Hurley .stop = nfp_flower_stop,
1020fd0dd1abSJohn Hurley
10210c665e2bSJakub Kicinski .netdev_event = nfp_flower_netdev_event,
10220c665e2bSJakub Kicinski
10231025351aSSimon Horman .ctrl_msg_rx = nfp_flower_cmsg_rx,
10241025351aSSimon Horman
102524a021edSSimon Horman .sriov_enable = nfp_flower_sriov_enable,
102624a021edSSimon Horman .sriov_disable = nfp_flower_sriov_disable,
102724a021edSSimon Horman
10281025351aSSimon Horman .eswitch_mode_get = eswitch_mode_get,
1029f41dd059SJohn Hurley .dev_get = nfp_flower_dev_get,
10308a276873SPieter Jansen van Vuuren
10318a276873SPieter Jansen van Vuuren .setup_tc = nfp_flower_setup_tc,
10321025351aSSimon Horman };
1033