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