162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/bpf.h>
562306a36Sopenharmony_ci#include <linux/bitops.h>
662306a36Sopenharmony_ci#include <linux/bug.h>
762306a36Sopenharmony_ci#include <linux/jiffies.h>
862306a36Sopenharmony_ci#include <linux/skbuff.h>
962306a36Sopenharmony_ci#include <linux/timekeeping.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "../ccm.h"
1262306a36Sopenharmony_ci#include "../nfp_app.h"
1362306a36Sopenharmony_ci#include "../nfp_net.h"
1462306a36Sopenharmony_ci#include "fw.h"
1562306a36Sopenharmony_ci#include "main.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic struct sk_buff *
1862306a36Sopenharmony_cinfp_bpf_cmsg_alloc(struct nfp_app_bpf *bpf, unsigned int size)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	struct sk_buff *skb;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	skb = nfp_app_ctrl_msg_alloc(bpf->app, size, GFP_KERNEL);
2362306a36Sopenharmony_ci	skb_put(skb, size);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	return skb;
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic unsigned int
2962306a36Sopenharmony_cinfp_bpf_cmsg_map_req_size(struct nfp_app_bpf *bpf, unsigned int n)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	unsigned int size;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	size = sizeof(struct cmsg_req_map_op);
3462306a36Sopenharmony_ci	size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	return size;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic struct sk_buff *
4062306a36Sopenharmony_cinfp_bpf_cmsg_map_req_alloc(struct nfp_app_bpf *bpf, unsigned int n)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return nfp_bpf_cmsg_alloc(bpf, nfp_bpf_cmsg_map_req_size(bpf, n));
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic unsigned int
4662306a36Sopenharmony_cinfp_bpf_cmsg_map_reply_size(struct nfp_app_bpf *bpf, unsigned int n)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	unsigned int size;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	size = sizeof(struct cmsg_reply_map_op);
5162306a36Sopenharmony_ci	size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	return size;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int
5762306a36Sopenharmony_cinfp_bpf_ctrl_rc_to_errno(struct nfp_app_bpf *bpf,
5862306a36Sopenharmony_ci			 struct cmsg_reply_map_simple *reply)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	static const int res_table[] = {
6162306a36Sopenharmony_ci		[CMSG_RC_SUCCESS]	= 0,
6262306a36Sopenharmony_ci		[CMSG_RC_ERR_MAP_FD]	= -EBADFD,
6362306a36Sopenharmony_ci		[CMSG_RC_ERR_MAP_NOENT]	= -ENOENT,
6462306a36Sopenharmony_ci		[CMSG_RC_ERR_MAP_ERR]	= -EINVAL,
6562306a36Sopenharmony_ci		[CMSG_RC_ERR_MAP_PARSE]	= -EIO,
6662306a36Sopenharmony_ci		[CMSG_RC_ERR_MAP_EXIST]	= -EEXIST,
6762306a36Sopenharmony_ci		[CMSG_RC_ERR_MAP_NOMEM]	= -ENOMEM,
6862306a36Sopenharmony_ci		[CMSG_RC_ERR_MAP_E2BIG]	= -E2BIG,
6962306a36Sopenharmony_ci	};
7062306a36Sopenharmony_ci	u32 rc;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	rc = be32_to_cpu(reply->rc);
7362306a36Sopenharmony_ci	if (rc >= ARRAY_SIZE(res_table)) {
7462306a36Sopenharmony_ci		cmsg_warn(bpf, "FW responded with invalid status: %u\n", rc);
7562306a36Sopenharmony_ci		return -EIO;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return res_table[rc];
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cilong long int
8262306a36Sopenharmony_cinfp_bpf_ctrl_alloc_map(struct nfp_app_bpf *bpf, struct bpf_map *map)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct cmsg_reply_map_alloc_tbl *reply;
8562306a36Sopenharmony_ci	struct cmsg_req_map_alloc_tbl *req;
8662306a36Sopenharmony_ci	struct sk_buff *skb;
8762306a36Sopenharmony_ci	u32 tid;
8862306a36Sopenharmony_ci	int err;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	skb = nfp_bpf_cmsg_alloc(bpf, sizeof(*req));
9162306a36Sopenharmony_ci	if (!skb)
9262306a36Sopenharmony_ci		return -ENOMEM;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	req = (void *)skb->data;
9562306a36Sopenharmony_ci	req->key_size = cpu_to_be32(map->key_size);
9662306a36Sopenharmony_ci	req->value_size = cpu_to_be32(map->value_size);
9762306a36Sopenharmony_ci	req->max_entries = cpu_to_be32(map->max_entries);
9862306a36Sopenharmony_ci	req->map_type = cpu_to_be32(map->map_type);
9962306a36Sopenharmony_ci	req->map_flags = 0;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	skb = nfp_ccm_communicate(&bpf->ccm, skb, NFP_CCM_TYPE_BPF_MAP_ALLOC,
10262306a36Sopenharmony_ci				  sizeof(*reply));
10362306a36Sopenharmony_ci	if (IS_ERR(skb))
10462306a36Sopenharmony_ci		return PTR_ERR(skb);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	reply = (void *)skb->data;
10762306a36Sopenharmony_ci	err = nfp_bpf_ctrl_rc_to_errno(bpf, &reply->reply_hdr);
10862306a36Sopenharmony_ci	if (err)
10962306a36Sopenharmony_ci		goto err_free;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	tid = be32_to_cpu(reply->tid);
11262306a36Sopenharmony_ci	dev_consume_skb_any(skb);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return tid;
11562306a36Sopenharmony_cierr_free:
11662306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
11762306a36Sopenharmony_ci	return err;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_civoid nfp_bpf_ctrl_free_map(struct nfp_app_bpf *bpf, struct nfp_bpf_map *nfp_map)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct cmsg_reply_map_free_tbl *reply;
12362306a36Sopenharmony_ci	struct cmsg_req_map_free_tbl *req;
12462306a36Sopenharmony_ci	struct sk_buff *skb;
12562306a36Sopenharmony_ci	int err;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	skb = nfp_bpf_cmsg_alloc(bpf, sizeof(*req));
12862306a36Sopenharmony_ci	if (!skb) {
12962306a36Sopenharmony_ci		cmsg_warn(bpf, "leaking map - failed to allocate msg\n");
13062306a36Sopenharmony_ci		return;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	req = (void *)skb->data;
13462306a36Sopenharmony_ci	req->tid = cpu_to_be32(nfp_map->tid);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	skb = nfp_ccm_communicate(&bpf->ccm, skb, NFP_CCM_TYPE_BPF_MAP_FREE,
13762306a36Sopenharmony_ci				  sizeof(*reply));
13862306a36Sopenharmony_ci	if (IS_ERR(skb)) {
13962306a36Sopenharmony_ci		cmsg_warn(bpf, "leaking map - I/O error\n");
14062306a36Sopenharmony_ci		return;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	reply = (void *)skb->data;
14462306a36Sopenharmony_ci	err = nfp_bpf_ctrl_rc_to_errno(bpf, &reply->reply_hdr);
14562306a36Sopenharmony_ci	if (err)
14662306a36Sopenharmony_ci		cmsg_warn(bpf, "leaking map - FW responded with: %d\n", err);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	dev_consume_skb_any(skb);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void *
15262306a36Sopenharmony_cinfp_bpf_ctrl_req_key(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req,
15362306a36Sopenharmony_ci		     unsigned int n)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	return &req->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n];
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic void *
15962306a36Sopenharmony_cinfp_bpf_ctrl_req_val(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req,
16062306a36Sopenharmony_ci		     unsigned int n)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	return &req->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n];
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic void *
16662306a36Sopenharmony_cinfp_bpf_ctrl_reply_key(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply,
16762306a36Sopenharmony_ci		       unsigned int n)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	return &reply->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n];
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic void *
17362306a36Sopenharmony_cinfp_bpf_ctrl_reply_val(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply,
17462306a36Sopenharmony_ci		       unsigned int n)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	return &reply->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n];
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic bool nfp_bpf_ctrl_op_cache_invalidate(enum nfp_ccm_type op)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	return op == NFP_CCM_TYPE_BPF_MAP_UPDATE ||
18262306a36Sopenharmony_ci	       op == NFP_CCM_TYPE_BPF_MAP_DELETE;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic bool nfp_bpf_ctrl_op_cache_capable(enum nfp_ccm_type op)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	return op == NFP_CCM_TYPE_BPF_MAP_LOOKUP ||
18862306a36Sopenharmony_ci	       op == NFP_CCM_TYPE_BPF_MAP_GETNEXT;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic bool nfp_bpf_ctrl_op_cache_fill(enum nfp_ccm_type op)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	return op == NFP_CCM_TYPE_BPF_MAP_GETFIRST ||
19462306a36Sopenharmony_ci	       op == NFP_CCM_TYPE_BPF_MAP_GETNEXT;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic unsigned int
19862306a36Sopenharmony_cinfp_bpf_ctrl_op_cache_get(struct nfp_bpf_map *nfp_map, enum nfp_ccm_type op,
19962306a36Sopenharmony_ci			  const u8 *key, u8 *out_key, u8 *out_value,
20062306a36Sopenharmony_ci			  u32 *cache_gen)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct bpf_map *map = &nfp_map->offmap->map;
20362306a36Sopenharmony_ci	struct nfp_app_bpf *bpf = nfp_map->bpf;
20462306a36Sopenharmony_ci	unsigned int i, count, n_entries;
20562306a36Sopenharmony_ci	struct cmsg_reply_map_op *reply;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	n_entries = nfp_bpf_ctrl_op_cache_fill(op) ? bpf->cmsg_cache_cnt : 1;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	spin_lock(&nfp_map->cache_lock);
21062306a36Sopenharmony_ci	*cache_gen = nfp_map->cache_gen;
21162306a36Sopenharmony_ci	if (nfp_map->cache_blockers)
21262306a36Sopenharmony_ci		n_entries = 1;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (nfp_bpf_ctrl_op_cache_invalidate(op))
21562306a36Sopenharmony_ci		goto exit_block;
21662306a36Sopenharmony_ci	if (!nfp_bpf_ctrl_op_cache_capable(op))
21762306a36Sopenharmony_ci		goto exit_unlock;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (!nfp_map->cache)
22062306a36Sopenharmony_ci		goto exit_unlock;
22162306a36Sopenharmony_ci	if (nfp_map->cache_to < ktime_get_ns())
22262306a36Sopenharmony_ci		goto exit_invalidate;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	reply = (void *)nfp_map->cache->data;
22562306a36Sopenharmony_ci	count = be32_to_cpu(reply->count);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
22862306a36Sopenharmony_ci		void *cached_key;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		cached_key = nfp_bpf_ctrl_reply_key(bpf, reply, i);
23162306a36Sopenharmony_ci		if (memcmp(cached_key, key, map->key_size))
23262306a36Sopenharmony_ci			continue;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		if (op == NFP_CCM_TYPE_BPF_MAP_LOOKUP)
23562306a36Sopenharmony_ci			memcpy(out_value, nfp_bpf_ctrl_reply_val(bpf, reply, i),
23662306a36Sopenharmony_ci			       map->value_size);
23762306a36Sopenharmony_ci		if (op == NFP_CCM_TYPE_BPF_MAP_GETNEXT) {
23862306a36Sopenharmony_ci			if (i + 1 == count)
23962306a36Sopenharmony_ci				break;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci			memcpy(out_key,
24262306a36Sopenharmony_ci			       nfp_bpf_ctrl_reply_key(bpf, reply, i + 1),
24362306a36Sopenharmony_ci			       map->key_size);
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		n_entries = 0;
24762306a36Sopenharmony_ci		goto exit_unlock;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci	goto exit_unlock;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ciexit_block:
25262306a36Sopenharmony_ci	nfp_map->cache_blockers++;
25362306a36Sopenharmony_ciexit_invalidate:
25462306a36Sopenharmony_ci	dev_consume_skb_any(nfp_map->cache);
25562306a36Sopenharmony_ci	nfp_map->cache = NULL;
25662306a36Sopenharmony_ciexit_unlock:
25762306a36Sopenharmony_ci	spin_unlock(&nfp_map->cache_lock);
25862306a36Sopenharmony_ci	return n_entries;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic void
26262306a36Sopenharmony_cinfp_bpf_ctrl_op_cache_put(struct nfp_bpf_map *nfp_map, enum nfp_ccm_type op,
26362306a36Sopenharmony_ci			  struct sk_buff *skb, u32 cache_gen)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	bool blocker, filler;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	blocker = nfp_bpf_ctrl_op_cache_invalidate(op);
26862306a36Sopenharmony_ci	filler = nfp_bpf_ctrl_op_cache_fill(op);
26962306a36Sopenharmony_ci	if (blocker || filler) {
27062306a36Sopenharmony_ci		u64 to = 0;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		if (filler)
27362306a36Sopenharmony_ci			to = ktime_get_ns() + NFP_BPF_MAP_CACHE_TIME_NS;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		spin_lock(&nfp_map->cache_lock);
27662306a36Sopenharmony_ci		if (blocker) {
27762306a36Sopenharmony_ci			nfp_map->cache_blockers--;
27862306a36Sopenharmony_ci			nfp_map->cache_gen++;
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci		if (filler && !nfp_map->cache_blockers &&
28162306a36Sopenharmony_ci		    nfp_map->cache_gen == cache_gen) {
28262306a36Sopenharmony_ci			nfp_map->cache_to = to;
28362306a36Sopenharmony_ci			swap(nfp_map->cache, skb);
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci		spin_unlock(&nfp_map->cache_lock);
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	dev_consume_skb_any(skb);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic int
29262306a36Sopenharmony_cinfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap, enum nfp_ccm_type op,
29362306a36Sopenharmony_ci		      u8 *key, u8 *value, u64 flags, u8 *out_key, u8 *out_value)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct nfp_bpf_map *nfp_map = offmap->dev_priv;
29662306a36Sopenharmony_ci	unsigned int n_entries, reply_entries, count;
29762306a36Sopenharmony_ci	struct nfp_app_bpf *bpf = nfp_map->bpf;
29862306a36Sopenharmony_ci	struct bpf_map *map = &offmap->map;
29962306a36Sopenharmony_ci	struct cmsg_reply_map_op *reply;
30062306a36Sopenharmony_ci	struct cmsg_req_map_op *req;
30162306a36Sopenharmony_ci	struct sk_buff *skb;
30262306a36Sopenharmony_ci	u32 cache_gen;
30362306a36Sopenharmony_ci	int err;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* FW messages have no space for more than 32 bits of flags */
30662306a36Sopenharmony_ci	if (flags >> 32)
30762306a36Sopenharmony_ci		return -EOPNOTSUPP;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* Handle op cache */
31062306a36Sopenharmony_ci	n_entries = nfp_bpf_ctrl_op_cache_get(nfp_map, op, key, out_key,
31162306a36Sopenharmony_ci					      out_value, &cache_gen);
31262306a36Sopenharmony_ci	if (!n_entries)
31362306a36Sopenharmony_ci		return 0;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	skb = nfp_bpf_cmsg_map_req_alloc(bpf, 1);
31662306a36Sopenharmony_ci	if (!skb) {
31762306a36Sopenharmony_ci		err = -ENOMEM;
31862306a36Sopenharmony_ci		goto err_cache_put;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	req = (void *)skb->data;
32262306a36Sopenharmony_ci	req->tid = cpu_to_be32(nfp_map->tid);
32362306a36Sopenharmony_ci	req->count = cpu_to_be32(n_entries);
32462306a36Sopenharmony_ci	req->flags = cpu_to_be32(flags);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* Copy inputs */
32762306a36Sopenharmony_ci	if (key)
32862306a36Sopenharmony_ci		memcpy(nfp_bpf_ctrl_req_key(bpf, req, 0), key, map->key_size);
32962306a36Sopenharmony_ci	if (value)
33062306a36Sopenharmony_ci		memcpy(nfp_bpf_ctrl_req_val(bpf, req, 0), value,
33162306a36Sopenharmony_ci		       map->value_size);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	skb = nfp_ccm_communicate(&bpf->ccm, skb, op, 0);
33462306a36Sopenharmony_ci	if (IS_ERR(skb)) {
33562306a36Sopenharmony_ci		err = PTR_ERR(skb);
33662306a36Sopenharmony_ci		goto err_cache_put;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (skb->len < sizeof(*reply)) {
34062306a36Sopenharmony_ci		cmsg_warn(bpf, "cmsg drop - type 0x%02x too short %d!\n",
34162306a36Sopenharmony_ci			  op, skb->len);
34262306a36Sopenharmony_ci		err = -EIO;
34362306a36Sopenharmony_ci		goto err_free;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	reply = (void *)skb->data;
34762306a36Sopenharmony_ci	count = be32_to_cpu(reply->count);
34862306a36Sopenharmony_ci	err = nfp_bpf_ctrl_rc_to_errno(bpf, &reply->reply_hdr);
34962306a36Sopenharmony_ci	/* FW responds with message sized to hold the good entries,
35062306a36Sopenharmony_ci	 * plus one extra entry if there was an error.
35162306a36Sopenharmony_ci	 */
35262306a36Sopenharmony_ci	reply_entries = count + !!err;
35362306a36Sopenharmony_ci	if (n_entries > 1 && count)
35462306a36Sopenharmony_ci		err = 0;
35562306a36Sopenharmony_ci	if (err)
35662306a36Sopenharmony_ci		goto err_free;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (skb->len != nfp_bpf_cmsg_map_reply_size(bpf, reply_entries)) {
35962306a36Sopenharmony_ci		cmsg_warn(bpf, "cmsg drop - type 0x%02x too short %d for %d entries!\n",
36062306a36Sopenharmony_ci			  op, skb->len, reply_entries);
36162306a36Sopenharmony_ci		err = -EIO;
36262306a36Sopenharmony_ci		goto err_free;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Copy outputs */
36662306a36Sopenharmony_ci	if (out_key)
36762306a36Sopenharmony_ci		memcpy(out_key, nfp_bpf_ctrl_reply_key(bpf, reply, 0),
36862306a36Sopenharmony_ci		       map->key_size);
36962306a36Sopenharmony_ci	if (out_value)
37062306a36Sopenharmony_ci		memcpy(out_value, nfp_bpf_ctrl_reply_val(bpf, reply, 0),
37162306a36Sopenharmony_ci		       map->value_size);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	nfp_bpf_ctrl_op_cache_put(nfp_map, op, skb, cache_gen);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	return 0;
37662306a36Sopenharmony_cierr_free:
37762306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
37862306a36Sopenharmony_cierr_cache_put:
37962306a36Sopenharmony_ci	nfp_bpf_ctrl_op_cache_put(nfp_map, op, NULL, cache_gen);
38062306a36Sopenharmony_ci	return err;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ciint nfp_bpf_ctrl_update_entry(struct bpf_offloaded_map *offmap,
38462306a36Sopenharmony_ci			      void *key, void *value, u64 flags)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_UPDATE,
38762306a36Sopenharmony_ci				     key, value, flags, NULL, NULL);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ciint nfp_bpf_ctrl_del_entry(struct bpf_offloaded_map *offmap, void *key)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_DELETE,
39362306a36Sopenharmony_ci				     key, NULL, 0, NULL, NULL);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ciint nfp_bpf_ctrl_lookup_entry(struct bpf_offloaded_map *offmap,
39762306a36Sopenharmony_ci			      void *key, void *value)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_LOOKUP,
40062306a36Sopenharmony_ci				     key, NULL, 0, NULL, value);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ciint nfp_bpf_ctrl_getfirst_entry(struct bpf_offloaded_map *offmap,
40462306a36Sopenharmony_ci				void *next_key)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_GETFIRST,
40762306a36Sopenharmony_ci				     NULL, NULL, 0, next_key, NULL);
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ciint nfp_bpf_ctrl_getnext_entry(struct bpf_offloaded_map *offmap,
41162306a36Sopenharmony_ci			       void *key, void *next_key)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	return nfp_bpf_ctrl_entry_op(offmap, NFP_CCM_TYPE_BPF_MAP_GETNEXT,
41462306a36Sopenharmony_ci				     key, NULL, 0, next_key, NULL);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ciunsigned int nfp_bpf_ctrl_cmsg_min_mtu(struct nfp_app_bpf *bpf)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	return max(nfp_bpf_cmsg_map_req_size(bpf, 1),
42062306a36Sopenharmony_ci		   nfp_bpf_cmsg_map_reply_size(bpf, 1));
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ciunsigned int nfp_bpf_ctrl_cmsg_mtu(struct nfp_app_bpf *bpf)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	return max3(NFP_NET_DEFAULT_MTU,
42662306a36Sopenharmony_ci		    nfp_bpf_cmsg_map_req_size(bpf, NFP_BPF_MAP_CACHE_CNT),
42762306a36Sopenharmony_ci		    nfp_bpf_cmsg_map_reply_size(bpf, NFP_BPF_MAP_CACHE_CNT));
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ciunsigned int nfp_bpf_ctrl_cmsg_cache_cnt(struct nfp_app_bpf *bpf)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	unsigned int mtu, req_max, reply_max, entry_sz;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	mtu = bpf->app->ctrl->dp.mtu;
43562306a36Sopenharmony_ci	entry_sz = bpf->cmsg_key_sz + bpf->cmsg_val_sz;
43662306a36Sopenharmony_ci	req_max = (mtu - sizeof(struct cmsg_req_map_op)) / entry_sz;
43762306a36Sopenharmony_ci	reply_max = (mtu - sizeof(struct cmsg_reply_map_op)) / entry_sz;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return min3(req_max, reply_max, NFP_BPF_MAP_CACHE_CNT);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_civoid nfp_bpf_ctrl_msg_rx(struct nfp_app *app, struct sk_buff *skb)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct nfp_app_bpf *bpf = app->priv;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (unlikely(skb->len < sizeof(struct cmsg_reply_map_simple))) {
44762306a36Sopenharmony_ci		cmsg_warn(bpf, "cmsg drop - too short %d!\n", skb->len);
44862306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
44962306a36Sopenharmony_ci		return;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (nfp_ccm_get_type(skb) == NFP_CCM_TYPE_BPF_BPF_EVENT) {
45362306a36Sopenharmony_ci		if (!nfp_bpf_event_output(bpf, skb->data, skb->len))
45462306a36Sopenharmony_ci			dev_consume_skb_any(skb);
45562306a36Sopenharmony_ci		else
45662306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
45762306a36Sopenharmony_ci		return;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	nfp_ccm_rx(&bpf->ccm, skb);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_civoid
46462306a36Sopenharmony_cinfp_bpf_ctrl_msg_rx_raw(struct nfp_app *app, const void *data, unsigned int len)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	const struct nfp_ccm_hdr *hdr = data;
46762306a36Sopenharmony_ci	struct nfp_app_bpf *bpf = app->priv;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (unlikely(len < sizeof(struct cmsg_reply_map_simple))) {
47062306a36Sopenharmony_ci		cmsg_warn(bpf, "cmsg drop - too short %d!\n", len);
47162306a36Sopenharmony_ci		return;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (hdr->type == NFP_CCM_TYPE_BPF_BPF_EVENT)
47562306a36Sopenharmony_ci		nfp_bpf_event_output(bpf, data, len);
47662306a36Sopenharmony_ci	else
47762306a36Sopenharmony_ci		cmsg_warn(bpf, "cmsg drop - msg type %d with raw buffer!\n",
47862306a36Sopenharmony_ci			  hdr->type);
47962306a36Sopenharmony_ci}
480