18aa0cb00SJakub Kicinski /*
28aa0cb00SJakub Kicinski  * Copyright (C) 2017 Netronome Systems, Inc.
38aa0cb00SJakub Kicinski  *
48aa0cb00SJakub Kicinski  * This software is dual licensed under the GNU General License Version 2,
58aa0cb00SJakub Kicinski  * June 1991 as shown in the file COPYING in the top-level directory of this
68aa0cb00SJakub Kicinski  * source tree or the BSD 2-Clause License provided below.  You have the
78aa0cb00SJakub Kicinski  * option to license this software under the complete terms of either license.
88aa0cb00SJakub Kicinski  *
98aa0cb00SJakub Kicinski  * The BSD 2-Clause License:
108aa0cb00SJakub Kicinski  *
118aa0cb00SJakub Kicinski  *     Redistribution and use in source and binary forms, with or
128aa0cb00SJakub Kicinski  *     without modification, are permitted provided that the following
138aa0cb00SJakub Kicinski  *     conditions are met:
148aa0cb00SJakub Kicinski  *
158aa0cb00SJakub Kicinski  *      1. Redistributions of source code must retain the above
168aa0cb00SJakub Kicinski  *         copyright notice, this list of conditions and the following
178aa0cb00SJakub Kicinski  *         disclaimer.
188aa0cb00SJakub Kicinski  *
198aa0cb00SJakub Kicinski  *      2. Redistributions in binary form must reproduce the above
208aa0cb00SJakub Kicinski  *         copyright notice, this list of conditions and the following
218aa0cb00SJakub Kicinski  *         disclaimer in the documentation and/or other materials
228aa0cb00SJakub Kicinski  *         provided with the distribution.
238aa0cb00SJakub Kicinski  *
248aa0cb00SJakub Kicinski  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
258aa0cb00SJakub Kicinski  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
268aa0cb00SJakub Kicinski  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
278aa0cb00SJakub Kicinski  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
288aa0cb00SJakub Kicinski  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
298aa0cb00SJakub Kicinski  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
308aa0cb00SJakub Kicinski  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
318aa0cb00SJakub Kicinski  * SOFTWARE.
328aa0cb00SJakub Kicinski  */
338aa0cb00SJakub Kicinski 
34bb45e51cSJakub Kicinski #include <net/pkt_cls.h>
35bb45e51cSJakub Kicinski 
368aa0cb00SJakub Kicinski #include "../nfpcore/nfp_cpp.h"
3777a844eeSJakub Kicinski #include "../nfpcore/nfp_nffw.h"
388aa0cb00SJakub Kicinski #include "../nfp_app.h"
398aa0cb00SJakub Kicinski #include "../nfp_main.h"
408aa0cb00SJakub Kicinski #include "../nfp_net.h"
418aa0cb00SJakub Kicinski #include "../nfp_port.h"
420d49eaf4SJakub Kicinski #include "fw.h"
43bb45e51cSJakub Kicinski #include "main.h"
44bb45e51cSJakub Kicinski 
45bb45e51cSJakub Kicinski static bool nfp_net_ebpf_capable(struct nfp_net *nn)
46bb45e51cSJakub Kicinski {
470f6cf4ddSJakub Kicinski #ifdef __LITTLE_ENDIAN
48bb45e51cSJakub Kicinski 	if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
49bb45e51cSJakub Kicinski 	    nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
50bb45e51cSJakub Kicinski 		return true;
510f6cf4ddSJakub Kicinski #endif
52bb45e51cSJakub Kicinski 	return false;
53bb45e51cSJakub Kicinski }
54bb45e51cSJakub Kicinski 
55bb45e51cSJakub Kicinski static int
56bb45e51cSJakub Kicinski nfp_bpf_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
57bb45e51cSJakub Kicinski 		    struct bpf_prog *prog)
58bb45e51cSJakub Kicinski {
599ce7a956SJakub Kicinski 	bool running, xdp_running;
60bb45e51cSJakub Kicinski 	int ret;
61bb45e51cSJakub Kicinski 
62bb45e51cSJakub Kicinski 	if (!nfp_net_ebpf_capable(nn))
63bb45e51cSJakub Kicinski 		return -EINVAL;
64bb45e51cSJakub Kicinski 
659ce7a956SJakub Kicinski 	running = nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
669ce7a956SJakub Kicinski 	xdp_running = running && nn->dp.bpf_offload_xdp;
67bb45e51cSJakub Kicinski 
689ce7a956SJakub Kicinski 	if (!prog && !xdp_running)
699ce7a956SJakub Kicinski 		return 0;
709ce7a956SJakub Kicinski 	if (prog && running && !xdp_running)
719ce7a956SJakub Kicinski 		return -EBUSY;
729ce7a956SJakub Kicinski 
73e4a91cd5SJakub Kicinski 	ret = nfp_net_bpf_offload(nn, prog, running);
74bb45e51cSJakub Kicinski 	/* Stop offload if replace not possible */
759ce7a956SJakub Kicinski 	if (ret && prog)
76bb45e51cSJakub Kicinski 		nfp_bpf_xdp_offload(app, nn, NULL);
779ce7a956SJakub Kicinski 
78bb45e51cSJakub Kicinski 	nn->dp.bpf_offload_xdp = prog && !ret;
79bb45e51cSJakub Kicinski 	return ret;
80bb45e51cSJakub Kicinski }
81bb45e51cSJakub Kicinski 
82bb45e51cSJakub Kicinski static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
83bb45e51cSJakub Kicinski {
84bb45e51cSJakub Kicinski 	return nfp_net_ebpf_capable(nn) ? "BPF" : "";
85bb45e51cSJakub Kicinski }
868aa0cb00SJakub Kicinski 
874f83435aSJakub Kicinski static int
884f83435aSJakub Kicinski nfp_bpf_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
894f83435aSJakub Kicinski {
902314fe9eSJakub Kicinski 	struct nfp_bpf_vnic *bv;
914f83435aSJakub Kicinski 	int err;
924f83435aSJakub Kicinski 
932314fe9eSJakub Kicinski 	bv = kzalloc(sizeof(*bv), GFP_KERNEL);
942314fe9eSJakub Kicinski 	if (!bv)
954f83435aSJakub Kicinski 		return -ENOMEM;
962314fe9eSJakub Kicinski 	nn->app_priv = bv;
974f83435aSJakub Kicinski 
984f83435aSJakub Kicinski 	err = nfp_app_nic_vnic_alloc(app, nn, id);
994f83435aSJakub Kicinski 	if (err)
1004f83435aSJakub Kicinski 		goto err_free_priv;
1014f83435aSJakub Kicinski 
1022314fe9eSJakub Kicinski 	bv->start_off = nn_readw(nn, NFP_NET_CFG_BPF_START);
1032314fe9eSJakub Kicinski 	bv->tgt_done = nn_readw(nn, NFP_NET_CFG_BPF_DONE);
1042314fe9eSJakub Kicinski 
1054f83435aSJakub Kicinski 	return 0;
1064f83435aSJakub Kicinski err_free_priv:
1074f83435aSJakub Kicinski 	kfree(nn->app_priv);
1084f83435aSJakub Kicinski 	return err;
1094f83435aSJakub Kicinski }
1104f83435aSJakub Kicinski 
1114f83435aSJakub Kicinski static void nfp_bpf_vnic_free(struct nfp_app *app, struct nfp_net *nn)
1124f83435aSJakub Kicinski {
1134f83435aSJakub Kicinski 	struct nfp_bpf_vnic *bv = nn->app_priv;
1144f83435aSJakub Kicinski 
1154f83435aSJakub Kicinski 	WARN_ON(bv->tc_prog);
1164f83435aSJakub Kicinski 	kfree(bv);
1174f83435aSJakub Kicinski }
1184f83435aSJakub Kicinski 
11990d97315SJiri Pirko static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
12090d97315SJiri Pirko 				     void *type_data, void *cb_priv)
121bb45e51cSJakub Kicinski {
122de4784caSJiri Pirko 	struct tc_cls_bpf_offload *cls_bpf = type_data;
12390d97315SJiri Pirko 	struct nfp_net *nn = cb_priv;
124d3f89b98SJakub Kicinski 	struct bpf_prog *oldprog;
125d3f89b98SJakub Kicinski 	struct nfp_bpf_vnic *bv;
126d3f89b98SJakub Kicinski 	int err;
127bb45e51cSJakub Kicinski 
1289ce7a956SJakub Kicinski 	if (type != TC_SETUP_CLSBPF ||
1299ce7a956SJakub Kicinski 	    !tc_can_offload(nn->dp.netdev) ||
1309ce7a956SJakub Kicinski 	    !nfp_net_ebpf_capable(nn) ||
1315fd9fc4eSJiri Pirko 	    cls_bpf->common.protocol != htons(ETH_P_ALL) ||
1325fd9fc4eSJiri Pirko 	    cls_bpf->common.chain_index)
133bb45e51cSJakub Kicinski 		return -EOPNOTSUPP;
134f449657fSJakub Kicinski 
135012bb8a8SJakub Kicinski 	/* Only support TC direct action */
136012bb8a8SJakub Kicinski 	if (!cls_bpf->exts_integrated ||
137012bb8a8SJakub Kicinski 	    tcf_exts_has_actions(cls_bpf->exts)) {
138012bb8a8SJakub Kicinski 		nn_err(nn, "only direct action with no legacy actions supported\n");
139012bb8a8SJakub Kicinski 		return -EOPNOTSUPP;
140012bb8a8SJakub Kicinski 	}
141012bb8a8SJakub Kicinski 
142102740bdSJakub Kicinski 	if (cls_bpf->command != TC_CLSBPF_OFFLOAD)
14390d97315SJiri Pirko 		return -EOPNOTSUPP;
144102740bdSJakub Kicinski 
145d3f89b98SJakub Kicinski 	bv = nn->app_priv;
146d3f89b98SJakub Kicinski 	oldprog = cls_bpf->oldprog;
147d3f89b98SJakub Kicinski 
148d3f89b98SJakub Kicinski 	/* Don't remove if oldprog doesn't match driver's state */
149d3f89b98SJakub Kicinski 	if (bv->tc_prog != oldprog) {
150d3f89b98SJakub Kicinski 		oldprog = NULL;
151d3f89b98SJakub Kicinski 		if (!cls_bpf->prog)
152d3f89b98SJakub Kicinski 			return 0;
15390d97315SJiri Pirko 	}
154d3f89b98SJakub Kicinski 
155d3f89b98SJakub Kicinski 	err = nfp_net_bpf_offload(nn, cls_bpf->prog, oldprog);
156d3f89b98SJakub Kicinski 	if (err)
157d3f89b98SJakub Kicinski 		return err;
158d3f89b98SJakub Kicinski 
159d3f89b98SJakub Kicinski 	bv->tc_prog = cls_bpf->prog;
160d3f89b98SJakub Kicinski 	return 0;
16190d97315SJiri Pirko }
16290d97315SJiri Pirko 
16390d97315SJiri Pirko static int nfp_bpf_setup_tc_block(struct net_device *netdev,
16490d97315SJiri Pirko 				  struct tc_block_offload *f)
16590d97315SJiri Pirko {
16690d97315SJiri Pirko 	struct nfp_net *nn = netdev_priv(netdev);
16790d97315SJiri Pirko 
16890d97315SJiri Pirko 	if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
16990d97315SJiri Pirko 		return -EOPNOTSUPP;
17090d97315SJiri Pirko 
17190d97315SJiri Pirko 	switch (f->command) {
17290d97315SJiri Pirko 	case TC_BLOCK_BIND:
17390d97315SJiri Pirko 		return tcf_block_cb_register(f->block,
17490d97315SJiri Pirko 					     nfp_bpf_setup_tc_block_cb,
17590d97315SJiri Pirko 					     nn, nn);
17690d97315SJiri Pirko 	case TC_BLOCK_UNBIND:
17790d97315SJiri Pirko 		tcf_block_cb_unregister(f->block,
17890d97315SJiri Pirko 					nfp_bpf_setup_tc_block_cb,
17990d97315SJiri Pirko 					nn);
18090d97315SJiri Pirko 		return 0;
18190d97315SJiri Pirko 	default:
18290d97315SJiri Pirko 		return -EOPNOTSUPP;
18390d97315SJiri Pirko 	}
18490d97315SJiri Pirko }
18590d97315SJiri Pirko 
18690d97315SJiri Pirko static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
18790d97315SJiri Pirko 			    enum tc_setup_type type, void *type_data)
18890d97315SJiri Pirko {
18990d97315SJiri Pirko 	switch (type) {
19090d97315SJiri Pirko 	case TC_SETUP_BLOCK:
19190d97315SJiri Pirko 		return nfp_bpf_setup_tc_block(netdev, type_data);
19290d97315SJiri Pirko 	default:
19390d97315SJiri Pirko 		return -EOPNOTSUPP;
19490d97315SJiri Pirko 	}
195bb45e51cSJakub Kicinski }
196bb45e51cSJakub Kicinski 
197bb45e51cSJakub Kicinski static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn)
198bb45e51cSJakub Kicinski {
199a0f30c97SJakub Kicinski 	struct nfp_bpf_vnic *bv = nn->app_priv;
200a0f30c97SJakub Kicinski 
201a0f30c97SJakub Kicinski 	return !!bv->tc_prog;
202bb45e51cSJakub Kicinski }
203bb45e51cSJakub Kicinski 
2040d49eaf4SJakub Kicinski static int
205ccbdc596SJakub Kicinski nfp_bpf_change_mtu(struct nfp_app *app, struct net_device *netdev, int new_mtu)
206ccbdc596SJakub Kicinski {
207ccbdc596SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
208ccbdc596SJakub Kicinski 	unsigned int max_mtu;
209ccbdc596SJakub Kicinski 
210ccbdc596SJakub Kicinski 	if (~nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF)
211ccbdc596SJakub Kicinski 		return 0;
212ccbdc596SJakub Kicinski 
213ccbdc596SJakub Kicinski 	max_mtu = nn_readb(nn, NFP_NET_CFG_BPF_INL_MTU) * 64 - 32;
214ccbdc596SJakub Kicinski 	if (new_mtu > max_mtu) {
215ccbdc596SJakub Kicinski 		nn_info(nn, "BPF offload active, MTU over %u not supported\n",
216ccbdc596SJakub Kicinski 			max_mtu);
217ccbdc596SJakub Kicinski 		return -EBUSY;
218ccbdc596SJakub Kicinski 	}
219ccbdc596SJakub Kicinski 	return 0;
220ccbdc596SJakub Kicinski }
221ccbdc596SJakub Kicinski 
222ccbdc596SJakub Kicinski static int
2230d49eaf4SJakub Kicinski nfp_bpf_parse_cap_adjust_head(struct nfp_app_bpf *bpf, void __iomem *value,
2240d49eaf4SJakub Kicinski 			      u32 length)
2250d49eaf4SJakub Kicinski {
2260d49eaf4SJakub Kicinski 	struct nfp_bpf_cap_tlv_adjust_head __iomem *cap = value;
2270d49eaf4SJakub Kicinski 	struct nfp_cpp *cpp = bpf->app->pf->cpp;
2280d49eaf4SJakub Kicinski 
2290d49eaf4SJakub Kicinski 	if (length < sizeof(*cap)) {
2300d49eaf4SJakub Kicinski 		nfp_err(cpp, "truncated adjust_head TLV: %d\n", length);
2310d49eaf4SJakub Kicinski 		return -EINVAL;
2320d49eaf4SJakub Kicinski 	}
2330d49eaf4SJakub Kicinski 
2340d49eaf4SJakub Kicinski 	bpf->adjust_head.flags = readl(&cap->flags);
2350d49eaf4SJakub Kicinski 	bpf->adjust_head.off_min = readl(&cap->off_min);
2360d49eaf4SJakub Kicinski 	bpf->adjust_head.off_max = readl(&cap->off_max);
2378231f844SJakub Kicinski 	bpf->adjust_head.guaranteed_sub = readl(&cap->guaranteed_sub);
2388231f844SJakub Kicinski 	bpf->adjust_head.guaranteed_add = readl(&cap->guaranteed_add);
2390d49eaf4SJakub Kicinski 
2400d49eaf4SJakub Kicinski 	if (bpf->adjust_head.off_min > bpf->adjust_head.off_max) {
2410d49eaf4SJakub Kicinski 		nfp_err(cpp, "invalid adjust_head TLV: min > max\n");
2420d49eaf4SJakub Kicinski 		return -EINVAL;
2430d49eaf4SJakub Kicinski 	}
2440d49eaf4SJakub Kicinski 	if (!FIELD_FIT(UR_REG_IMM_MAX, bpf->adjust_head.off_min) ||
2450d49eaf4SJakub Kicinski 	    !FIELD_FIT(UR_REG_IMM_MAX, bpf->adjust_head.off_max)) {
2460d49eaf4SJakub Kicinski 		nfp_warn(cpp, "disabling adjust_head - driver expects min/max to fit in as immediates\n");
2470d49eaf4SJakub Kicinski 		memset(&bpf->adjust_head, 0, sizeof(bpf->adjust_head));
2480d49eaf4SJakub Kicinski 		return 0;
2490d49eaf4SJakub Kicinski 	}
2500d49eaf4SJakub Kicinski 
2510d49eaf4SJakub Kicinski 	return 0;
2520d49eaf4SJakub Kicinski }
2530d49eaf4SJakub Kicinski 
2549d080d5dSJakub Kicinski static int
2559d080d5dSJakub Kicinski nfp_bpf_parse_cap_func(struct nfp_app_bpf *bpf, void __iomem *value, u32 length)
2569d080d5dSJakub Kicinski {
2579d080d5dSJakub Kicinski 	struct nfp_bpf_cap_tlv_func __iomem *cap = value;
2589d080d5dSJakub Kicinski 
2599d080d5dSJakub Kicinski 	if (length < sizeof(*cap)) {
2609d080d5dSJakub Kicinski 		nfp_err(bpf->app->cpp, "truncated function TLV: %d\n", length);
2619d080d5dSJakub Kicinski 		return -EINVAL;
2629d080d5dSJakub Kicinski 	}
2639d080d5dSJakub Kicinski 
2649d080d5dSJakub Kicinski 	switch (readl(&cap->func_id)) {
2659d080d5dSJakub Kicinski 	case BPF_FUNC_map_lookup_elem:
2669d080d5dSJakub Kicinski 		bpf->helpers.map_lookup = readl(&cap->func_addr);
2679d080d5dSJakub Kicinski 		break;
2689d080d5dSJakub Kicinski 	}
2699d080d5dSJakub Kicinski 
2709d080d5dSJakub Kicinski 	return 0;
2719d080d5dSJakub Kicinski }
2729d080d5dSJakub Kicinski 
2739d080d5dSJakub Kicinski static int
2749d080d5dSJakub Kicinski nfp_bpf_parse_cap_maps(struct nfp_app_bpf *bpf, void __iomem *value, u32 length)
2759d080d5dSJakub Kicinski {
2769d080d5dSJakub Kicinski 	struct nfp_bpf_cap_tlv_maps __iomem *cap = value;
2779d080d5dSJakub Kicinski 
2789d080d5dSJakub Kicinski 	if (length < sizeof(*cap)) {
2799d080d5dSJakub Kicinski 		nfp_err(bpf->app->cpp, "truncated maps TLV: %d\n", length);
2809d080d5dSJakub Kicinski 		return -EINVAL;
2819d080d5dSJakub Kicinski 	}
2829d080d5dSJakub Kicinski 
2839d080d5dSJakub Kicinski 	bpf->maps.types = readl(&cap->types);
2849d080d5dSJakub Kicinski 	bpf->maps.max_maps = readl(&cap->max_maps);
2859d080d5dSJakub Kicinski 	bpf->maps.max_elems = readl(&cap->max_elems);
2869d080d5dSJakub Kicinski 	bpf->maps.max_key_sz = readl(&cap->max_key_sz);
2879d080d5dSJakub Kicinski 	bpf->maps.max_val_sz = readl(&cap->max_val_sz);
2889d080d5dSJakub Kicinski 	bpf->maps.max_elem_sz = readl(&cap->max_elem_sz);
2899d080d5dSJakub Kicinski 
2909d080d5dSJakub Kicinski 	return 0;
2919d080d5dSJakub Kicinski }
2929d080d5dSJakub Kicinski 
29377a844eeSJakub Kicinski static int nfp_bpf_parse_capabilities(struct nfp_app *app)
29477a844eeSJakub Kicinski {
29577a844eeSJakub Kicinski 	struct nfp_cpp *cpp = app->pf->cpp;
29677a844eeSJakub Kicinski 	struct nfp_cpp_area *area;
29777a844eeSJakub Kicinski 	u8 __iomem *mem, *start;
29877a844eeSJakub Kicinski 
29977a844eeSJakub Kicinski 	mem = nfp_rtsym_map(app->pf->rtbl, "_abi_bpf_capabilities", "bpf.cap",
30077a844eeSJakub Kicinski 			    8, &area);
30177a844eeSJakub Kicinski 	if (IS_ERR(mem))
30277a844eeSJakub Kicinski 		return PTR_ERR(mem) == -ENOENT ? 0 : PTR_ERR(mem);
30377a844eeSJakub Kicinski 
30477a844eeSJakub Kicinski 	start = mem;
30577a844eeSJakub Kicinski 	while (mem - start + 8 < nfp_cpp_area_size(area)) {
3060d49eaf4SJakub Kicinski 		u8 __iomem *value;
30777a844eeSJakub Kicinski 		u32 type, length;
30877a844eeSJakub Kicinski 
30977a844eeSJakub Kicinski 		type = readl(mem);
31077a844eeSJakub Kicinski 		length = readl(mem + 4);
3110d49eaf4SJakub Kicinski 		value = mem + 8;
31277a844eeSJakub Kicinski 
31377a844eeSJakub Kicinski 		mem += 8 + length;
31477a844eeSJakub Kicinski 		if (mem - start > nfp_cpp_area_size(area))
31577a844eeSJakub Kicinski 			goto err_release_free;
31677a844eeSJakub Kicinski 
31777a844eeSJakub Kicinski 		switch (type) {
3189d080d5dSJakub Kicinski 		case NFP_BPF_CAP_TYPE_FUNC:
3199d080d5dSJakub Kicinski 			if (nfp_bpf_parse_cap_func(app->priv, value, length))
3209d080d5dSJakub Kicinski 				goto err_release_free;
3219d080d5dSJakub Kicinski 			break;
3220d49eaf4SJakub Kicinski 		case NFP_BPF_CAP_TYPE_ADJUST_HEAD:
3230d49eaf4SJakub Kicinski 			if (nfp_bpf_parse_cap_adjust_head(app->priv, value,
3240d49eaf4SJakub Kicinski 							  length))
3250d49eaf4SJakub Kicinski 				goto err_release_free;
3260d49eaf4SJakub Kicinski 			break;
3279d080d5dSJakub Kicinski 		case NFP_BPF_CAP_TYPE_MAPS:
3289d080d5dSJakub Kicinski 			if (nfp_bpf_parse_cap_maps(app->priv, value, length))
3299d080d5dSJakub Kicinski 				goto err_release_free;
3309d080d5dSJakub Kicinski 			break;
33177a844eeSJakub Kicinski 		default:
33277a844eeSJakub Kicinski 			nfp_dbg(cpp, "unknown BPF capability: %d\n", type);
33377a844eeSJakub Kicinski 			break;
33477a844eeSJakub Kicinski 		}
33577a844eeSJakub Kicinski 	}
33677a844eeSJakub Kicinski 	if (mem - start != nfp_cpp_area_size(area)) {
3370bce7c9aSJakub Kicinski 		nfp_err(cpp, "BPF capabilities left after parsing, parsed:%zd total length:%zu\n",
33877a844eeSJakub Kicinski 			mem - start, nfp_cpp_area_size(area));
33977a844eeSJakub Kicinski 		goto err_release_free;
34077a844eeSJakub Kicinski 	}
34177a844eeSJakub Kicinski 
34277a844eeSJakub Kicinski 	nfp_cpp_area_release_free(area);
34377a844eeSJakub Kicinski 
34477a844eeSJakub Kicinski 	return 0;
34577a844eeSJakub Kicinski 
34677a844eeSJakub Kicinski err_release_free:
3470bce7c9aSJakub Kicinski 	nfp_err(cpp, "invalid BPF capabilities at offset:%zd\n", mem - start);
34877a844eeSJakub Kicinski 	nfp_cpp_area_release_free(area);
34977a844eeSJakub Kicinski 	return -EINVAL;
35077a844eeSJakub Kicinski }
35177a844eeSJakub Kicinski 
35277a844eeSJakub Kicinski static int nfp_bpf_init(struct nfp_app *app)
35377a844eeSJakub Kicinski {
35477a844eeSJakub Kicinski 	struct nfp_app_bpf *bpf;
35577a844eeSJakub Kicinski 	int err;
35677a844eeSJakub Kicinski 
35777a844eeSJakub Kicinski 	bpf = kzalloc(sizeof(*bpf), GFP_KERNEL);
35877a844eeSJakub Kicinski 	if (!bpf)
35977a844eeSJakub Kicinski 		return -ENOMEM;
36077a844eeSJakub Kicinski 	bpf->app = app;
36177a844eeSJakub Kicinski 	app->priv = bpf;
36277a844eeSJakub Kicinski 
363d48ae231SJakub Kicinski 	skb_queue_head_init(&bpf->cmsg_replies);
364d48ae231SJakub Kicinski 	init_waitqueue_head(&bpf->cmsg_wq);
3654da98eeaSJakub Kicinski 	INIT_LIST_HEAD(&bpf->map_list);
3664da98eeaSJakub Kicinski 
36777a844eeSJakub Kicinski 	err = nfp_bpf_parse_capabilities(app);
36877a844eeSJakub Kicinski 	if (err)
36977a844eeSJakub Kicinski 		goto err_free_bpf;
37077a844eeSJakub Kicinski 
37177a844eeSJakub Kicinski 	return 0;
37277a844eeSJakub Kicinski 
37377a844eeSJakub Kicinski err_free_bpf:
37477a844eeSJakub Kicinski 	kfree(bpf);
37577a844eeSJakub Kicinski 	return err;
37677a844eeSJakub Kicinski }
37777a844eeSJakub Kicinski 
37877a844eeSJakub Kicinski static void nfp_bpf_clean(struct nfp_app *app)
37977a844eeSJakub Kicinski {
3804da98eeaSJakub Kicinski 	struct nfp_app_bpf *bpf = app->priv;
3814da98eeaSJakub Kicinski 
382d48ae231SJakub Kicinski 	WARN_ON(!skb_queue_empty(&bpf->cmsg_replies));
3834da98eeaSJakub Kicinski 	WARN_ON(!list_empty(&bpf->map_list));
3841bba4c41SJakub Kicinski 	WARN_ON(bpf->maps_in_use || bpf->map_elems_in_use);
3854da98eeaSJakub Kicinski 	kfree(bpf);
38677a844eeSJakub Kicinski }
38777a844eeSJakub Kicinski 
3888aa0cb00SJakub Kicinski const struct nfp_app_type app_bpf = {
3898aa0cb00SJakub Kicinski 	.id		= NFP_APP_BPF_NIC,
3902707d6f1SJakub Kicinski 	.name		= "ebpf",
3918aa0cb00SJakub Kicinski 
39281bd5dedSJakub Kicinski 	.ctrl_cap_mask	= 0,
39378a0a65fSJakub Kicinski 
39477a844eeSJakub Kicinski 	.init		= nfp_bpf_init,
39577a844eeSJakub Kicinski 	.clean		= nfp_bpf_clean,
39677a844eeSJakub Kicinski 
397ccbdc596SJakub Kicinski 	.change_mtu	= nfp_bpf_change_mtu,
398ccbdc596SJakub Kicinski 
399bb45e51cSJakub Kicinski 	.extra_cap	= nfp_bpf_extra_cap,
400bb45e51cSJakub Kicinski 
4014f83435aSJakub Kicinski 	.vnic_alloc	= nfp_bpf_vnic_alloc,
4024f83435aSJakub Kicinski 	.vnic_free	= nfp_bpf_vnic_free,
403bb45e51cSJakub Kicinski 
404d48ae231SJakub Kicinski 	.ctrl_msg_rx	= nfp_bpf_ctrl_msg_rx,
405d48ae231SJakub Kicinski 
406bb45e51cSJakub Kicinski 	.setup_tc	= nfp_bpf_setup_tc,
407bb45e51cSJakub Kicinski 	.tc_busy	= nfp_bpf_tc_busy,
408af93d15aSJakub Kicinski 	.bpf		= nfp_ndo_bpf,
409bb45e51cSJakub Kicinski 	.xdp_offload	= nfp_bpf_xdp_offload,
4108aa0cb00SJakub Kicinski };
411