xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/nfp_app.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
196de2506SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
296de2506SJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
37ac9ebd5SJakub Kicinski 
44c7787baSMark Brown #include <linux/bug.h>
5e1740fb6SJakub Kicinski #include <linux/lockdep.h>
6e1740fb6SJakub Kicinski #include <linux/rcupdate.h>
702082701SJakub Kicinski #include <linux/skbuff.h>
87ac9ebd5SJakub Kicinski #include <linux/slab.h>
97ac9ebd5SJakub Kicinski 
108aa0cb00SJakub Kicinski #include "nfpcore/nfp_cpp.h"
1176abc0f6SJakub Kicinski #include "nfpcore/nfp_nffw.h"
127ac9ebd5SJakub Kicinski #include "nfp_app.h"
137ac9ebd5SJakub Kicinski #include "nfp_main.h"
149e4c2cfcSJakub Kicinski #include "nfp_net.h"
155de73ee4SSimon Horman #include "nfp_net_repr.h"
1621f31bc0SJakub Kicinski #include "nfp_port.h"
177ac9ebd5SJakub Kicinski 
188aa0cb00SJakub Kicinski static const struct nfp_app_type *apps[] = {
192c4197a0SJakub Kicinski 	[NFP_APP_CORE_NIC]	= &app_nic,
2043b45245SJakub Kicinski #ifdef CONFIG_BPF_SYSCALL
212c4197a0SJakub Kicinski 	[NFP_APP_BPF_NIC]	= &app_bpf,
2243b45245SJakub Kicinski #else
2343b45245SJakub Kicinski 	[NFP_APP_BPF_NIC]	= &app_nic,
2443b45245SJakub Kicinski #endif
2557ae676eSJakub Kicinski #ifdef CONFIG_NFP_APP_FLOWER
262c4197a0SJakub Kicinski 	[NFP_APP_FLOWER_NIC]	= &app_flower,
2757ae676eSJakub Kicinski #endif
28c4c8f39aSJakub Kicinski #ifdef CONFIG_NFP_APP_ABM_NIC
29c4c8f39aSJakub Kicinski 	[NFP_APP_ACTIVE_BUFFER_MGMT_NIC] = &app_abm,
30c4c8f39aSJakub Kicinski #endif
318aa0cb00SJakub Kicinski };
328aa0cb00SJakub Kicinski 
nfp_check_rhashtable_empty(void * ptr,void * arg)33c01d0efaSPieter Jansen van Vuuren void nfp_check_rhashtable_empty(void *ptr, void *arg)
34c01d0efaSPieter Jansen van Vuuren {
35c01d0efaSPieter Jansen van Vuuren 	WARN_ON_ONCE(1);
36c01d0efaSPieter Jansen van Vuuren }
37c01d0efaSPieter Jansen van Vuuren 
nfp_app_from_netdev(struct net_device * netdev)389e4c2cfcSJakub Kicinski struct nfp_app *nfp_app_from_netdev(struct net_device *netdev)
399e4c2cfcSJakub Kicinski {
409e4c2cfcSJakub Kicinski 	if (nfp_netdev_is_nfp_net(netdev)) {
419e4c2cfcSJakub Kicinski 		struct nfp_net *nn = netdev_priv(netdev);
429e4c2cfcSJakub Kicinski 
439e4c2cfcSJakub Kicinski 		return nn->app;
449e4c2cfcSJakub Kicinski 	}
459e4c2cfcSJakub Kicinski 
469e4c2cfcSJakub Kicinski 	if (nfp_netdev_is_nfp_repr(netdev)) {
479e4c2cfcSJakub Kicinski 		struct nfp_repr *repr = netdev_priv(netdev);
489e4c2cfcSJakub Kicinski 
499e4c2cfcSJakub Kicinski 		return repr->app;
509e4c2cfcSJakub Kicinski 	}
519e4c2cfcSJakub Kicinski 
529e4c2cfcSJakub Kicinski 	WARN(1, "Unknown netdev type for nfp_app\n");
539e4c2cfcSJakub Kicinski 
549e4c2cfcSJakub Kicinski 	return NULL;
559e4c2cfcSJakub Kicinski }
569e4c2cfcSJakub Kicinski 
nfp_app_mip_name(struct nfp_app * app)5776abc0f6SJakub Kicinski const char *nfp_app_mip_name(struct nfp_app *app)
5876abc0f6SJakub Kicinski {
5976abc0f6SJakub Kicinski 	if (!app || !app->pf->mip)
6076abc0f6SJakub Kicinski 		return "";
6176abc0f6SJakub Kicinski 	return nfp_mip_name(app->pf->mip);
6276abc0f6SJakub Kicinski }
6376abc0f6SJakub Kicinski 
nfp_app_ndo_init(struct net_device * netdev)644612bebfSJakub Kicinski int nfp_app_ndo_init(struct net_device *netdev)
654612bebfSJakub Kicinski {
664612bebfSJakub Kicinski 	struct nfp_app *app = nfp_app_from_netdev(netdev);
674612bebfSJakub Kicinski 
684612bebfSJakub Kicinski 	if (!app || !app->type->ndo_init)
694612bebfSJakub Kicinski 		return 0;
704612bebfSJakub Kicinski 	return app->type->ndo_init(app, netdev);
714612bebfSJakub Kicinski }
724612bebfSJakub Kicinski 
nfp_app_ndo_uninit(struct net_device * netdev)734612bebfSJakub Kicinski void nfp_app_ndo_uninit(struct net_device *netdev)
744612bebfSJakub Kicinski {
754612bebfSJakub Kicinski 	struct nfp_app *app = nfp_app_from_netdev(netdev);
764612bebfSJakub Kicinski 
774612bebfSJakub Kicinski 	if (app && app->type->ndo_uninit)
784612bebfSJakub Kicinski 		app->type->ndo_uninit(app, netdev);
794612bebfSJakub Kicinski }
804612bebfSJakub Kicinski 
nfp_app_port_get_stats(struct nfp_port * port,u64 * data)8121f31bc0SJakub Kicinski u64 *nfp_app_port_get_stats(struct nfp_port *port, u64 *data)
8221f31bc0SJakub Kicinski {
8321f31bc0SJakub Kicinski 	if (!port || !port->app || !port->app->type->port_get_stats)
8421f31bc0SJakub Kicinski 		return data;
8521f31bc0SJakub Kicinski 	return port->app->type->port_get_stats(port->app, port, data);
8621f31bc0SJakub Kicinski }
8721f31bc0SJakub Kicinski 
nfp_app_port_get_stats_count(struct nfp_port * port)8821f31bc0SJakub Kicinski int nfp_app_port_get_stats_count(struct nfp_port *port)
8921f31bc0SJakub Kicinski {
9021f31bc0SJakub Kicinski 	if (!port || !port->app || !port->app->type->port_get_stats_count)
9121f31bc0SJakub Kicinski 		return 0;
9221f31bc0SJakub Kicinski 	return port->app->type->port_get_stats_count(port->app, port);
9321f31bc0SJakub Kicinski }
9421f31bc0SJakub Kicinski 
nfp_app_port_get_stats_strings(struct nfp_port * port,u8 * data)9521f31bc0SJakub Kicinski u8 *nfp_app_port_get_stats_strings(struct nfp_port *port, u8 *data)
9621f31bc0SJakub Kicinski {
9721f31bc0SJakub Kicinski 	if (!port || !port->app || !port->app->type->port_get_stats_strings)
9821f31bc0SJakub Kicinski 		return data;
9921f31bc0SJakub Kicinski 	return port->app->type->port_get_stats_strings(port->app, port, data);
10021f31bc0SJakub Kicinski }
10121f31bc0SJakub Kicinski 
102948faa46SSimon Horman struct sk_buff *
nfp_app_ctrl_msg_alloc(struct nfp_app * app,unsigned int size,gfp_t priority)103948faa46SSimon Horman nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size, gfp_t priority)
10402082701SJakub Kicinski {
10502082701SJakub Kicinski 	struct sk_buff *skb;
10602082701SJakub Kicinski 
10702082701SJakub Kicinski 	if (nfp_app_ctrl_has_meta(app))
10802082701SJakub Kicinski 		size += 8;
10902082701SJakub Kicinski 
110948faa46SSimon Horman 	skb = alloc_skb(size, priority);
11102082701SJakub Kicinski 	if (!skb)
11202082701SJakub Kicinski 		return NULL;
11302082701SJakub Kicinski 
11402082701SJakub Kicinski 	if (nfp_app_ctrl_has_meta(app))
11502082701SJakub Kicinski 		skb_reserve(skb, 8);
11602082701SJakub Kicinski 
11702082701SJakub Kicinski 	return skb;
11802082701SJakub Kicinski }
11902082701SJakub Kicinski 
1205de73ee4SSimon Horman struct nfp_reprs *
nfp_reprs_get_locked(struct nfp_app * app,enum nfp_repr_type type)121e1740fb6SJakub Kicinski nfp_reprs_get_locked(struct nfp_app *app, enum nfp_repr_type type)
122e1740fb6SJakub Kicinski {
123e1740fb6SJakub Kicinski 	return rcu_dereference_protected(app->reprs[type],
1248a38f2ccSJakub Kicinski 					 nfp_app_is_locked(app));
125e1740fb6SJakub Kicinski }
126e1740fb6SJakub Kicinski 
127e1740fb6SJakub Kicinski struct nfp_reprs *
nfp_app_reprs_set(struct nfp_app * app,enum nfp_repr_type type,struct nfp_reprs * reprs)1285de73ee4SSimon Horman nfp_app_reprs_set(struct nfp_app *app, enum nfp_repr_type type,
1295de73ee4SSimon Horman 		  struct nfp_reprs *reprs)
1305de73ee4SSimon Horman {
1315de73ee4SSimon Horman 	struct nfp_reprs *old;
1325de73ee4SSimon Horman 
133e1740fb6SJakub Kicinski 	old = nfp_reprs_get_locked(app, type);
13471844facSJakub Kicinski 	rtnl_lock();
1355de73ee4SSimon Horman 	rcu_assign_pointer(app->reprs[type], reprs);
13671844facSJakub Kicinski 	rtnl_unlock();
1375de73ee4SSimon Horman 
1385de73ee4SSimon Horman 	return old;
1395de73ee4SSimon Horman }
1405de73ee4SSimon Horman 
14151a6588eSJakub Kicinski static void
nfp_app_netdev_feat_change(struct nfp_app * app,struct net_device * netdev)14251a6588eSJakub Kicinski nfp_app_netdev_feat_change(struct nfp_app *app, struct net_device *netdev)
14351a6588eSJakub Kicinski {
14451a6588eSJakub Kicinski 	struct nfp_net *nn;
14551a6588eSJakub Kicinski 	unsigned int type;
14651a6588eSJakub Kicinski 
14751a6588eSJakub Kicinski 	if (!nfp_netdev_is_nfp_net(netdev))
14851a6588eSJakub Kicinski 		return;
14951a6588eSJakub Kicinski 	nn = netdev_priv(netdev);
15051a6588eSJakub Kicinski 	if (nn->app != app)
15151a6588eSJakub Kicinski 		return;
15251a6588eSJakub Kicinski 
15351a6588eSJakub Kicinski 	for (type = 0; type < __NFP_REPR_TYPE_MAX; type++) {
15451a6588eSJakub Kicinski 		struct nfp_reprs *reprs;
15551a6588eSJakub Kicinski 		unsigned int i;
15651a6588eSJakub Kicinski 
15751a6588eSJakub Kicinski 		reprs = rtnl_dereference(app->reprs[type]);
15851a6588eSJakub Kicinski 		if (!reprs)
15951a6588eSJakub Kicinski 			continue;
16051a6588eSJakub Kicinski 
16151a6588eSJakub Kicinski 		for (i = 0; i < reprs->num_reprs; i++) {
16251a6588eSJakub Kicinski 			struct net_device *repr;
16351a6588eSJakub Kicinski 
16451a6588eSJakub Kicinski 			repr = rtnl_dereference(reprs->reprs[i]);
16551a6588eSJakub Kicinski 			if (!repr)
16651a6588eSJakub Kicinski 				continue;
16751a6588eSJakub Kicinski 
16851a6588eSJakub Kicinski 			nfp_repr_transfer_features(repr, netdev);
16951a6588eSJakub Kicinski 		}
17051a6588eSJakub Kicinski 	}
17151a6588eSJakub Kicinski }
17251a6588eSJakub Kicinski 
1733e333590SJakub Kicinski static int
nfp_app_netdev_event(struct notifier_block * nb,unsigned long event,void * ptr)1743e333590SJakub Kicinski nfp_app_netdev_event(struct notifier_block *nb, unsigned long event, void *ptr)
1753e333590SJakub Kicinski {
1763e333590SJakub Kicinski 	struct net_device *netdev;
1773e333590SJakub Kicinski 	struct nfp_app *app;
1783e333590SJakub Kicinski 
1793e333590SJakub Kicinski 	netdev = netdev_notifier_info_to_dev(ptr);
1803e333590SJakub Kicinski 	app = container_of(nb, struct nfp_app, netdev_nb);
1813e333590SJakub Kicinski 
18251a6588eSJakub Kicinski 	/* Handle events common code is interested in */
18351a6588eSJakub Kicinski 	switch (event) {
18451a6588eSJakub Kicinski 	case NETDEV_FEAT_CHANGE:
18551a6588eSJakub Kicinski 		nfp_app_netdev_feat_change(app, netdev);
18651a6588eSJakub Kicinski 		break;
18751a6588eSJakub Kicinski 	}
18851a6588eSJakub Kicinski 
18951a6588eSJakub Kicinski 	/* Call offload specific handlers */
1903e333590SJakub Kicinski 	if (app->type->netdev_event)
1913e333590SJakub Kicinski 		return app->type->netdev_event(app, netdev, event, ptr);
1923e333590SJakub Kicinski 	return NOTIFY_DONE;
1933e333590SJakub Kicinski }
1943e333590SJakub Kicinski 
nfp_app_start(struct nfp_app * app,struct nfp_net * ctrl)1953e333590SJakub Kicinski int nfp_app_start(struct nfp_app *app, struct nfp_net *ctrl)
1963e333590SJakub Kicinski {
1973e333590SJakub Kicinski 	int err;
1983e333590SJakub Kicinski 
1993e333590SJakub Kicinski 	app->ctrl = ctrl;
2003e333590SJakub Kicinski 
2013e333590SJakub Kicinski 	if (app->type->start) {
2023e333590SJakub Kicinski 		err = app->type->start(app);
2033e333590SJakub Kicinski 		if (err)
2043e333590SJakub Kicinski 			return err;
2053e333590SJakub Kicinski 	}
2063e333590SJakub Kicinski 
2073e333590SJakub Kicinski 	app->netdev_nb.notifier_call = nfp_app_netdev_event;
2083e333590SJakub Kicinski 	err = register_netdevice_notifier(&app->netdev_nb);
2093e333590SJakub Kicinski 	if (err)
2103e333590SJakub Kicinski 		goto err_app_stop;
2113e333590SJakub Kicinski 
2123e333590SJakub Kicinski 	return 0;
2133e333590SJakub Kicinski 
2143e333590SJakub Kicinski err_app_stop:
2153e333590SJakub Kicinski 	if (app->type->stop)
2163e333590SJakub Kicinski 		app->type->stop(app);
2173e333590SJakub Kicinski 	return err;
2183e333590SJakub Kicinski }
2193e333590SJakub Kicinski 
nfp_app_stop(struct nfp_app * app)2203e333590SJakub Kicinski void nfp_app_stop(struct nfp_app *app)
2213e333590SJakub Kicinski {
2223e333590SJakub Kicinski 	unregister_netdevice_notifier(&app->netdev_nb);
2233e333590SJakub Kicinski 
2243e333590SJakub Kicinski 	if (app->type->stop)
2253e333590SJakub Kicinski 		app->type->stop(app);
2263e333590SJakub Kicinski }
2273e333590SJakub Kicinski 
nfp_app_alloc(struct nfp_pf * pf,enum nfp_app_id id)2288aa0cb00SJakub Kicinski struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id)
2297ac9ebd5SJakub Kicinski {
2307ac9ebd5SJakub Kicinski 	struct nfp_app *app;
2318aa0cb00SJakub Kicinski 
2322c4197a0SJakub Kicinski 	if (id >= ARRAY_SIZE(apps) || !apps[id]) {
233*ef2a95dbSJustin Stitt 		nfp_err(pf->cpp, "unknown FW app ID 0x%02x, driver too old or support for FW not built in\n", id);
2348aa0cb00SJakub Kicinski 		return ERR_PTR(-EINVAL);
2358aa0cb00SJakub Kicinski 	}
2368aa0cb00SJakub Kicinski 
2372c4197a0SJakub Kicinski 	if (WARN_ON(!apps[id]->name || !apps[id]->vnic_alloc))
2388aa0cb00SJakub Kicinski 		return ERR_PTR(-EINVAL);
23979ca38e8SJakub Kicinski 	if (WARN_ON(!apps[id]->ctrl_msg_rx && apps[id]->ctrl_msg_rx_raw))
24079ca38e8SJakub Kicinski 		return ERR_PTR(-EINVAL);
2417ac9ebd5SJakub Kicinski 
2427ac9ebd5SJakub Kicinski 	app = kzalloc(sizeof(*app), GFP_KERNEL);
2437ac9ebd5SJakub Kicinski 	if (!app)
2447ac9ebd5SJakub Kicinski 		return ERR_PTR(-ENOMEM);
2457ac9ebd5SJakub Kicinski 
2467ac9ebd5SJakub Kicinski 	app->pf = pf;
2477ac9ebd5SJakub Kicinski 	app->cpp = pf->cpp;
2487ac9ebd5SJakub Kicinski 	app->pdev = pf->pdev;
2492c4197a0SJakub Kicinski 	app->type = apps[id];
2507ac9ebd5SJakub Kicinski 
2517ac9ebd5SJakub Kicinski 	return app;
2527ac9ebd5SJakub Kicinski }
2537ac9ebd5SJakub Kicinski 
nfp_app_free(struct nfp_app * app)2547ac9ebd5SJakub Kicinski void nfp_app_free(struct nfp_app *app)
2557ac9ebd5SJakub Kicinski {
2567ac9ebd5SJakub Kicinski 	kfree(app);
2577ac9ebd5SJakub Kicinski }
258