18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 28c2ecf20Sopenharmony_ci/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/bpf.h> 58c2ecf20Sopenharmony_ci#include <linux/bitops.h> 68c2ecf20Sopenharmony_ci#include <linux/bug.h> 78c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 88c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 98c2ecf20Sopenharmony_ci#include <linux/timekeeping.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "../ccm.h" 128c2ecf20Sopenharmony_ci#include "../nfp_app.h" 138c2ecf20Sopenharmony_ci#include "../nfp_net.h" 148c2ecf20Sopenharmony_ci#include "fw.h" 158c2ecf20Sopenharmony_ci#include "main.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic struct sk_buff * 188c2ecf20Sopenharmony_cinfp_bpf_cmsg_alloc(struct nfp_app_bpf *bpf, unsigned int size) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct sk_buff *skb; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci skb = nfp_app_ctrl_msg_alloc(bpf->app, size, GFP_KERNEL); 238c2ecf20Sopenharmony_ci skb_put(skb, size); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return skb; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic unsigned int 298c2ecf20Sopenharmony_cinfp_bpf_cmsg_map_req_size(struct nfp_app_bpf *bpf, unsigned int n) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci unsigned int size; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci size = sizeof(struct cmsg_req_map_op); 348c2ecf20Sopenharmony_ci size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return size; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic struct sk_buff * 408c2ecf20Sopenharmony_cinfp_bpf_cmsg_map_req_alloc(struct nfp_app_bpf *bpf, unsigned int n) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci return nfp_bpf_cmsg_alloc(bpf, nfp_bpf_cmsg_map_req_size(bpf, n)); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic unsigned int 468c2ecf20Sopenharmony_cinfp_bpf_cmsg_map_reply_size(struct nfp_app_bpf *bpf, unsigned int n) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci unsigned int size; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci size = sizeof(struct cmsg_reply_map_op); 518c2ecf20Sopenharmony_ci size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return size; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int 578c2ecf20Sopenharmony_cinfp_bpf_ctrl_rc_to_errno(struct nfp_app_bpf *bpf, 588c2ecf20Sopenharmony_ci struct cmsg_reply_map_simple *reply) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci static const int res_table[] = { 618c2ecf20Sopenharmony_ci [CMSG_RC_SUCCESS] = 0, 628c2ecf20Sopenharmony_ci [CMSG_RC_ERR_MAP_FD] = -EBADFD, 638c2ecf20Sopenharmony_ci [CMSG_RC_ERR_MAP_NOENT] = -ENOENT, 648c2ecf20Sopenharmony_ci [CMSG_RC_ERR_MAP_ERR] = -EINVAL, 658c2ecf20Sopenharmony_ci [CMSG_RC_ERR_MAP_PARSE] = -EIO, 668c2ecf20Sopenharmony_ci [CMSG_RC_ERR_MAP_EXIST] = -EEXIST, 678c2ecf20Sopenharmony_ci [CMSG_RC_ERR_MAP_NOMEM] = -ENOMEM, 688c2ecf20Sopenharmony_ci [CMSG_RC_ERR_MAP_E2BIG] = -E2BIG, 698c2ecf20Sopenharmony_ci }; 708c2ecf20Sopenharmony_ci u32 rc; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci rc = be32_to_cpu(reply->rc); 738c2ecf20Sopenharmony_ci if (rc >= ARRAY_SIZE(res_table)) { 748c2ecf20Sopenharmony_ci cmsg_warn(bpf, "FW responded with invalid status: %u\n", rc); 758c2ecf20Sopenharmony_ci return -EIO; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return res_table[rc]; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cilong long int 828c2ecf20Sopenharmony_cinfp_bpf_ctrl_alloc_map(struct nfp_app_bpf *bpf, struct bpf_map *map) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct cmsg_reply_map_alloc_tbl *reply; 858c2ecf20Sopenharmony_ci struct cmsg_req_map_alloc_tbl *req; 868c2ecf20Sopenharmony_ci struct sk_buff *skb; 878c2ecf20Sopenharmony_ci u32 tid; 888c2ecf20Sopenharmony_ci int err; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci skb = nfp_bpf_cmsg_alloc(bpf, sizeof(*req)); 918c2ecf20Sopenharmony_ci if (!skb) 928c2ecf20Sopenharmony_ci return -ENOMEM; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci req = (void *)skb->data; 958c2ecf20Sopenharmony_ci req->key_size = cpu_to_be32(map->key_size); 968c2ecf20Sopenharmony_ci req->value_size = cpu_to_be32(map->value_size); 978c2ecf20Sopenharmony_ci req->max_entries = cpu_to_be32(map->max_entries); 988c2ecf20Sopenharmony_ci req->map_type = cpu_to_be32(map->map_type); 998c2ecf20Sopenharmony_ci req->map_flags = 0; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci skb = nfp_ccm_communicate(&bpf->ccm, skb, NFP_CCM_TYPE_BPF_MAP_ALLOC, 1028c2ecf20Sopenharmony_ci sizeof(*reply)); 1038c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 1048c2ecf20Sopenharmony_ci return PTR_ERR(skb); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci reply = (void *)skb->data; 1078c2ecf20Sopenharmony_ci err = nfp_bpf_ctrl_rc_to_errno(bpf, &reply->reply_hdr); 1088c2ecf20Sopenharmony_ci if (err) 1098c2ecf20Sopenharmony_ci goto err_free; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci tid = be32_to_cpu(reply->tid); 1128c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return tid; 1158c2ecf20Sopenharmony_cierr_free: 1168c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 1178c2ecf20Sopenharmony_ci return err; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_civoid nfp_bpf_ctrl_free_map(struct nfp_app_bpf *bpf, struct nfp_bpf_map *nfp_map) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct cmsg_reply_map_free_tbl *reply; 1238c2ecf20Sopenharmony_ci struct cmsg_req_map_free_tbl *req; 1248c2ecf20Sopenharmony_ci struct sk_buff *skb; 1258c2ecf20Sopenharmony_ci int err; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci skb = nfp_bpf_cmsg_alloc(bpf, sizeof(*req)); 1288c2ecf20Sopenharmony_ci if (!skb) { 1298c2ecf20Sopenharmony_ci cmsg_warn(bpf, "leaking map - failed to allocate msg\n"); 1308c2ecf20Sopenharmony_ci return; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci req = (void *)skb->data; 1348c2ecf20Sopenharmony_ci req->tid = cpu_to_be32(nfp_map->tid); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci skb = nfp_ccm_communicate(&bpf->ccm, skb, NFP_CCM_TYPE_BPF_MAP_FREE, 1378c2ecf20Sopenharmony_ci sizeof(*reply)); 1388c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 1398c2ecf20Sopenharmony_ci cmsg_warn(bpf, "leaking map - I/O error\n"); 1408c2ecf20Sopenharmony_ci return; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci reply = (void *)skb->data; 1448c2ecf20Sopenharmony_ci err = nfp_bpf_ctrl_rc_to_errno(bpf, &reply->reply_hdr); 1458c2ecf20Sopenharmony_ci if (err) 1468c2ecf20Sopenharmony_ci cmsg_warn(bpf, "leaking map - FW responded with: %d\n", err); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic void * 1528c2ecf20Sopenharmony_cinfp_bpf_ctrl_req_key(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req, 1538c2ecf20Sopenharmony_ci unsigned int n) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci return &req->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n]; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void * 1598c2ecf20Sopenharmony_cinfp_bpf_ctrl_req_val(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req, 1608c2ecf20Sopenharmony_ci unsigned int n) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return &req->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n]; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void * 1668c2ecf20Sopenharmony_cinfp_bpf_ctrl_reply_key(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply, 1678c2ecf20Sopenharmony_ci unsigned int n) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci return &reply->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n]; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void * 1738c2ecf20Sopenharmony_cinfp_bpf_ctrl_reply_val(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply, 1748c2ecf20Sopenharmony_ci unsigned int n) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci return &reply->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n]; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic bool nfp_bpf_ctrl_op_cache_invalidate(enum nfp_ccm_type op) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci return op == NFP_CCM_TYPE_BPF_MAP_UPDATE || 1828c2ecf20Sopenharmony_ci op == NFP_CCM_TYPE_BPF_MAP_DELETE; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic bool nfp_bpf_ctrl_op_cache_capable(enum nfp_ccm_type op) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci return op == NFP_CCM_TYPE_BPF_MAP_LOOKUP || 1888c2ecf20Sopenharmony_ci op == NFP_CCM_TYPE_BPF_MAP_GETNEXT; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic bool nfp_bpf_ctrl_op_cache_fill(enum nfp_ccm_type op) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci return op == NFP_CCM_TYPE_BPF_MAP_GETFIRST || 1948c2ecf20Sopenharmony_ci op == NFP_CCM_TYPE_BPF_MAP_GETNEXT; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic unsigned int 1988c2ecf20Sopenharmony_cinfp_bpf_ctrl_op_cache_get(struct nfp_bpf_map *nfp_map, enum nfp_ccm_type op, 1998c2ecf20Sopenharmony_ci const u8 *key, u8 *out_key, u8 *out_value, 2008c2ecf20Sopenharmony_ci u32 *cache_gen) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct bpf_map *map = &nfp_map->offmap->map; 2038c2ecf20Sopenharmony_ci struct nfp_app_bpf *bpf = nfp_map->bpf; 2048c2ecf20Sopenharmony_ci unsigned int i, count, n_entries; 2058c2ecf20Sopenharmony_ci struct cmsg_reply_map_op *reply; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci n_entries = nfp_bpf_ctrl_op_cache_fill(op) ? bpf->cmsg_cache_cnt : 1; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci spin_lock(&nfp_map->cache_lock); 2108c2ecf20Sopenharmony_ci *cache_gen = nfp_map->cache_gen; 2118c2ecf20Sopenharmony_ci if (nfp_map->cache_blockers) 2128c2ecf20Sopenharmony_ci n_entries = 1; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (nfp_bpf_ctrl_op_cache_invalidate(op)) 2158c2ecf20Sopenharmony_ci goto exit_block; 2168c2ecf20Sopenharmony_ci if (!nfp_bpf_ctrl_op_cache_capable(op)) 2178c2ecf20Sopenharmony_ci goto exit_unlock; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (!nfp_map->cache) 2208c2ecf20Sopenharmony_ci goto exit_unlock; 2218c2ecf20Sopenharmony_ci if (nfp_map->cache_to < ktime_get_ns()) 2228c2ecf20Sopenharmony_ci goto exit_invalidate; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci reply = (void *)nfp_map->cache->data; 2258c2ecf20Sopenharmony_ci count = be32_to_cpu(reply->count); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 2288c2ecf20Sopenharmony_ci void *cached_key; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci cached_key = nfp_bpf_ctrl_reply_key(bpf, reply, i); 2318c2ecf20Sopenharmony_ci if (memcmp(cached_key, key, map->key_size)) 2328c2ecf20Sopenharmony_ci continue; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (op == NFP_CCM_TYPE_BPF_MAP_LOOKUP) 2358c2ecf20Sopenharmony_ci memcpy(out_value, nfp_bpf_ctrl_reply_val(bpf, reply, i), 2368c2ecf20Sopenharmony_ci map->value_size); 2378c2ecf20Sopenharmony_ci if (op == NFP_CCM_TYPE_BPF_MAP_GETNEXT) { 2388c2ecf20Sopenharmony_ci if (i + 1 == count) 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci memcpy(out_key, 2428c2ecf20Sopenharmony_ci nfp_bpf_ctrl_reply_key(bpf, reply, i + 1), 2438c2ecf20Sopenharmony_ci map->key_size); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci n_entries = 0; 2478c2ecf20Sopenharmony_ci goto exit_unlock; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci goto exit_unlock; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciexit_block: 2528c2ecf20Sopenharmony_ci nfp_map->cache_blockers++; 2538c2ecf20Sopenharmony_ciexit_invalidate: 2548c2ecf20Sopenharmony_ci dev_consume_skb_any(nfp_map->cache); 2558c2ecf20Sopenharmony_ci nfp_map->cache = NULL; 2568c2ecf20Sopenharmony_ciexit_unlock: 2578c2ecf20Sopenharmony_ci spin_unlock(&nfp_map->cache_lock); 2588c2ecf20Sopenharmony_ci return n_entries; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void 2628c2ecf20Sopenharmony_cinfp_bpf_ctrl_op_cache_put(struct nfp_bpf_map *nfp_map, enum nfp_ccm_type op, 2638c2ecf20Sopenharmony_ci struct sk_buff *skb, u32 cache_gen) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci bool blocker, filler; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci blocker = nfp_bpf_ctrl_op_cache_invalidate(op); 2688c2ecf20Sopenharmony_ci filler = nfp_bpf_ctrl_op_cache_fill(op); 2698c2ecf20Sopenharmony_ci if (blocker || filler) { 2708c2ecf20Sopenharmony_ci u64 to = 0; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (filler) 2738c2ecf20Sopenharmony_ci to = ktime_get_ns() + NFP_BPF_MAP_CACHE_TIME_NS; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci spin_lock(&nfp_map->cache_lock); 2768c2ecf20Sopenharmony_ci if (blocker) { 2778c2ecf20Sopenharmony_ci nfp_map->cache_blockers--; 2788c2ecf20Sopenharmony_ci nfp_map->cache_gen++; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci if (filler && !nfp_map->cache_blockers && 2818c2ecf20Sopenharmony_ci nfp_map->cache_gen == cache_gen) { 2828c2ecf20Sopenharmony_ci nfp_map->cache_to = to; 2838c2ecf20Sopenharmony_ci swap(nfp_map->cache, skb); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci spin_unlock(&nfp_map->cache_lock); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int 2928c2ecf20Sopenharmony_cinfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap, enum nfp_ccm_type op, 2938c2ecf20Sopenharmony_ci u8 *key, u8 *value, u64 flags, u8 *out_key, u8 *out_value) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct nfp_bpf_map *nfp_map = offmap->dev_priv; 2968c2ecf20Sopenharmony_ci unsigned int n_entries, reply_entries, count; 2978c2ecf20Sopenharmony_ci struct nfp_app_bpf *bpf = nfp_map->bpf; 2988c2ecf20Sopenharmony_ci struct bpf_map *map = &offmap->map; 2998c2ecf20Sopenharmony_ci struct cmsg_reply_map_op *reply; 3008c2ecf20Sopenharmony_ci struct cmsg_req_map_op *req; 3018c2ecf20Sopenharmony_ci struct sk_buff *skb; 3028c2ecf20Sopenharmony_ci u32 cache_gen; 3038c2ecf20Sopenharmony_ci int err; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* FW messages have no space for more than 32 bits of flags */ 3068c2ecf20Sopenharmony_ci if (flags >> 32) 3078c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* Handle op cache */ 3108c2ecf20Sopenharmony_ci n_entries = nfp_bpf_ctrl_op_cache_get(nfp_map, op, key, out_key, 3118c2ecf20Sopenharmony_ci out_value, &cache_gen); 3128c2ecf20Sopenharmony_ci if (!n_entries) 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci skb = nfp_bpf_cmsg_map_req_alloc(bpf, 1); 3168c2ecf20Sopenharmony_ci if (!skb) { 3178c2ecf20Sopenharmony_ci err = -ENOMEM; 3188c2ecf20Sopenharmony_ci goto err_cache_put; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci req = (void *)skb->data; 3228c2ecf20Sopenharmony_ci req->tid = cpu_to_be32(nfp_map->tid); 3238c2ecf20Sopenharmony_ci req->count = cpu_to_be32(n_entries); 3248c2ecf20Sopenharmony_ci req->flags = cpu_to_be32(flags); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Copy inputs */ 3278c2ecf20Sopenharmony_ci if (key) 3288c2ecf20Sopenharmony_ci memcpy(nfp_bpf_ctrl_req_key(bpf, req, 0), key, map->key_size); 3298c2ecf20Sopenharmony_ci if (value) 3308c2ecf20Sopenharmony_ci memcpy(nfp_bpf_ctrl_req_val(bpf, req, 0), value, 3318c2ecf20Sopenharmony_ci map->value_size); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci skb = nfp_ccm_communicate(&bpf->ccm, skb, op, 0); 3348c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 3358c2ecf20Sopenharmony_ci err = PTR_ERR(skb); 3368c2ecf20Sopenharmony_ci goto err_cache_put; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (skb->len < sizeof(*reply)) { 3408c2ecf20Sopenharmony_ci cmsg_warn(bpf, "cmsg drop - type 0x%02x too short %d!\n", 3418c2ecf20Sopenharmony_ci op, skb->len); 3428c2ecf20Sopenharmony_ci err = -EIO; 3438c2ecf20Sopenharmony_ci goto err_free; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci reply = (void *)skb->data; 3478c2ecf20Sopenharmony_ci count = be32_to_cpu(reply->count); 3488c2ecf20Sopenharmony_ci err = nfp_bpf_ctrl_rc_to_errno(bpf, &reply->reply_hdr); 3498c2ecf20Sopenharmony_ci /* FW responds with message sized to hold the good entries, 3508c2ecf20Sopenharmony_ci * plus one extra entry if there was an error. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci reply_entries = count + !!err; 3538c2ecf20Sopenharmony_ci if (n_entries > 1 && count) 3548c2ecf20Sopenharmony_ci err = 0; 3558c2ecf20Sopenharmony_ci if (err) 3568c2ecf20Sopenharmony_ci goto err_free; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (skb->len != nfp_bpf_cmsg_map_reply_size(bpf, reply_entries)) { 3598c2ecf20Sopenharmony_ci cmsg_warn(bpf, "cmsg drop - type 0x%02x too short %d for %d entries!\n", 3608c2ecf20Sopenharmony_ci op, skb->len, reply_entries); 3618c2ecf20Sopenharmony_ci err = -EIO; 3628c2ecf20Sopenharmony_ci goto err_free; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* Copy outputs */ 3668c2ecf20Sopenharmony_ci if (out_key) 3678c2ecf20Sopenharmony_ci memcpy(out_key, nfp_bpf_ctrl_reply_key(bpf, reply, 0), 3688c2ecf20Sopenharmony_ci map->key_size); 3698c2ecf20Sopenharmony_ci if (out_value) 3708c2ecf20Sopenharmony_ci memcpy(out_value, nfp_bpf_ctrl_reply_val(bpf, reply, 0), 3718c2ecf20Sopenharmony_ci map->value_size); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci nfp_bpf_ctrl_op_cache_put(nfp_map, op, skb, cache_gen); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_cierr_free: 3778c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 3788c2ecf20Sopenharmony_cierr_cache_put: 3798c2ecf20Sopenharmony_ci nfp_bpf_ctrl_op_cache_put(nfp_map, op, NULL, cache_gen); 3808c2ecf20Sopenharmony_ci return err; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ciint nfp_bpf_ctrl_update_entry(struct bpf_offloaded_map *offmap, 3848c2ecf20Sopenharmony_ci void *key, void *value, u64 flags) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_UPDATE, 3878c2ecf20Sopenharmony_ci key, value, flags, NULL, NULL); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciint nfp_bpf_ctrl_del_entry(struct bpf_offloaded_map *offmap, void *key) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_DELETE, 3938c2ecf20Sopenharmony_ci key, NULL, 0, NULL, NULL); 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ciint nfp_bpf_ctrl_lookup_entry(struct bpf_offloaded_map *offmap, 3978c2ecf20Sopenharmony_ci void *key, void *value) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_LOOKUP, 4008c2ecf20Sopenharmony_ci key, NULL, 0, NULL, value); 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ciint nfp_bpf_ctrl_getfirst_entry(struct bpf_offloaded_map *offmap, 4048c2ecf20Sopenharmony_ci void *next_key) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_GETFIRST, 4078c2ecf20Sopenharmony_ci NULL, NULL, 0, next_key, NULL); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciint nfp_bpf_ctrl_getnext_entry(struct bpf_offloaded_map *offmap, 4118c2ecf20Sopenharmony_ci void *key, void *next_key) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_GETNEXT, 4148c2ecf20Sopenharmony_ci key, NULL, 0, next_key, NULL); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciunsigned int nfp_bpf_ctrl_cmsg_min_mtu(struct nfp_app_bpf *bpf) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return max(nfp_bpf_cmsg_map_req_size(bpf, 1), 4208c2ecf20Sopenharmony_ci nfp_bpf_cmsg_map_reply_size(bpf, 1)); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ciunsigned int nfp_bpf_ctrl_cmsg_mtu(struct nfp_app_bpf *bpf) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci return max3(NFP_NET_DEFAULT_MTU, 4268c2ecf20Sopenharmony_ci nfp_bpf_cmsg_map_req_size(bpf, NFP_BPF_MAP_CACHE_CNT), 4278c2ecf20Sopenharmony_ci nfp_bpf_cmsg_map_reply_size(bpf, NFP_BPF_MAP_CACHE_CNT)); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ciunsigned int nfp_bpf_ctrl_cmsg_cache_cnt(struct nfp_app_bpf *bpf) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci unsigned int mtu, req_max, reply_max, entry_sz; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci mtu = bpf->app->ctrl->dp.mtu; 4358c2ecf20Sopenharmony_ci entry_sz = bpf->cmsg_key_sz + bpf->cmsg_val_sz; 4368c2ecf20Sopenharmony_ci req_max = (mtu - sizeof(struct cmsg_req_map_op)) / entry_sz; 4378c2ecf20Sopenharmony_ci reply_max = (mtu - sizeof(struct cmsg_reply_map_op)) / entry_sz; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return min3(req_max, reply_max, NFP_BPF_MAP_CACHE_CNT); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_civoid nfp_bpf_ctrl_msg_rx(struct nfp_app *app, struct sk_buff *skb) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct nfp_app_bpf *bpf = app->priv; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (unlikely(skb->len < sizeof(struct cmsg_reply_map_simple))) { 4478c2ecf20Sopenharmony_ci cmsg_warn(bpf, "cmsg drop - too short %d!\n", skb->len); 4488c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 4498c2ecf20Sopenharmony_ci return; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (nfp_ccm_get_type(skb) == NFP_CCM_TYPE_BPF_BPF_EVENT) { 4538c2ecf20Sopenharmony_ci if (!nfp_bpf_event_output(bpf, skb->data, skb->len)) 4548c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 4578c2ecf20Sopenharmony_ci return; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci nfp_ccm_rx(&bpf->ccm, skb); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_civoid 4648c2ecf20Sopenharmony_cinfp_bpf_ctrl_msg_rx_raw(struct nfp_app *app, const void *data, unsigned int len) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci const struct nfp_ccm_hdr *hdr = data; 4678c2ecf20Sopenharmony_ci struct nfp_app_bpf *bpf = app->priv; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (unlikely(len < sizeof(struct cmsg_reply_map_simple))) { 4708c2ecf20Sopenharmony_ci cmsg_warn(bpf, "cmsg drop - too short %d!\n", len); 4718c2ecf20Sopenharmony_ci return; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (hdr->type == NFP_CCM_TYPE_BPF_BPF_EVENT) 4758c2ecf20Sopenharmony_ci nfp_bpf_event_output(bpf, data, len); 4768c2ecf20Sopenharmony_ci else 4778c2ecf20Sopenharmony_ci cmsg_warn(bpf, "cmsg drop - msg type %d with raw buffer!\n", 4788c2ecf20Sopenharmony_ci hdr->type); 4798c2ecf20Sopenharmony_ci} 480