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