Verify our current constraints on the location of the key
are met and generate the code for calling map lookup on
the datapath.

Signed-off-by: Jakub Kicinski <jakub.kicin...@netronome.com>
Reviewed-by: Quentin Monnet <quentin.mon...@netronome.com>
---
 drivers/net/ethernet/netronome/nfp/bpf/jit.c      | 51 +++++++++++++++++++++++
 drivers/net/ethernet/netronome/nfp/bpf/main.h     | 12 +++++-
 drivers/net/ethernet/netronome/nfp/bpf/verifier.c | 39 +++++++++++++++++
 3 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c 
b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
index 0de59f04da84..a037c0bb4185 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
@@ -1289,6 +1289,55 @@ static int adjust_head(struct nfp_prog *nfp_prog, struct 
nfp_insn_meta *meta)
        return 0;
 }
 
+static int
+map_lookup_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
+{
+       struct bpf_offloaded_map *offmap;
+       struct nfp_bpf_map *nfp_map;
+       bool load_lm_ptr;
+       u32 ret_tgt;
+       s64 lm_off;
+       swreg tid;
+
+       offmap = (struct bpf_offloaded_map *)meta->arg1.map_ptr;
+       nfp_map = offmap->dev_priv;
+
+       /* We only have to reload LM0 if the key is not at start of stack */
+       lm_off = nfp_prog->stack_depth;
+       lm_off += meta->arg2.var_off.value + meta->arg2.off;
+       load_lm_ptr = meta->arg2_var_off || lm_off;
+
+       /* Set LM0 to start of key */
+       if (load_lm_ptr)
+               emit_csr_wr(nfp_prog, reg_b(2 * 2), NFP_CSR_ACT_LM_ADDR0);
+
+       /* Load map ID into a register, it should actually fit as an immediate
+        * but in case it doesn't deal with it here, not in the delay slots.
+        */
+       tid = ur_load_imm_any(nfp_prog, nfp_map->tid, imm_a(nfp_prog));
+
+       emit_br(nfp_prog, BR_UNC, nfp_prog->bpf->helpers.map_lookup, 2);
+       ret_tgt = nfp_prog_current_offset(nfp_prog) + 2;
+
+       /* Load map ID into A0 */
+       wrp_mov(nfp_prog, reg_a(0), tid);
+
+       /* Load the return address into B0 */
+       wrp_immed(nfp_prog, reg_b(0), nfp_prog_current_offset(nfp_prog) + 1);
+
+       if (!nfp_prog_confirm_current_offset(nfp_prog, ret_tgt))
+               return -EINVAL;
+
+       /* Reset the LM0 pointer */
+       if (!load_lm_ptr)
+               return 0;
+
+       emit_csr_wr(nfp_prog, stack_reg(nfp_prog),  NFP_CSR_ACT_LM_ADDR0);
+       wrp_nops(nfp_prog, 3);
+
+       return 0;
+}
+
 /* --- Callbacks --- */
 static int mov_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
 {
@@ -2028,6 +2077,8 @@ static int call(struct nfp_prog *nfp_prog, struct 
nfp_insn_meta *meta)
        switch (meta->insn.imm) {
        case BPF_FUNC_xdp_adjust_head:
                return adjust_head(nfp_prog, meta);
+       case BPF_FUNC_map_lookup_elem:
+               return map_lookup_stack(nfp_prog, meta);
        default:
                WARN_ONCE(1, "verifier allowed unsupported function\n");
                return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h 
b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index 9dd76bf248b1..a3b428e1181d 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -180,9 +180,12 @@ typedef int (*instr_cb_t)(struct nfp_prog *, struct 
nfp_insn_meta *);
  * @ptr: pointer type for memory operations
  * @ldst_gather_len: memcpy length gathered from load/store sequence
  * @paired_st: the paired store insn at the head of the sequence
- * @arg2: arg2 for call instructions
  * @ptr_not_const: pointer is not always constant
  * @jmp_dst: destination info for jump instructions
+ * @func_id: function id for call instructions
+ * @arg1: arg1 for call instructions
+ * @arg2: arg2 for call instructions
+ * @arg2_var_off: arg2 changes stack offset on different paths
  * @off: index of first generated machine instruction (in nfp_prog.prog)
  * @n: eBPF instruction number
  * @flags: eBPF instruction extra optimization flags
@@ -200,7 +203,12 @@ struct nfp_insn_meta {
                        bool ptr_not_const;
                };
                struct nfp_insn_meta *jmp_dst;
-               struct bpf_reg_state arg2;
+               struct {
+                       u32 func_id;
+                       struct bpf_reg_state arg1;
+                       struct bpf_reg_state arg2;
+                       bool arg2_var_off;
+               };
        };
        unsigned int off;
        unsigned short n;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c 
b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
index d8870c2f11f3..589f56f9ea96 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
@@ -109,9 +109,11 @@ static int
 nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct bpf_verifier_env *env,
                   struct nfp_insn_meta *meta)
 {
+       const struct bpf_reg_state *reg1 = cur_regs(env) + BPF_REG_1;
        const struct bpf_reg_state *reg2 = cur_regs(env) + BPF_REG_2;
        struct nfp_app_bpf *bpf = nfp_prog->bpf;
        u32 func_id = meta->insn.imm;
+       s64 off, old_off;
 
        switch (func_id) {
        case BPF_FUNC_xdp_adjust_head:
@@ -126,11 +128,48 @@ nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct 
bpf_verifier_env *env,
 
                nfp_record_adjust_head(bpf, nfp_prog, meta, reg2);
                break;
+
+       case BPF_FUNC_map_lookup_elem:
+               if (!bpf->helpers.map_lookup) {
+                       pr_info("map_lookup: not supported by FW\n");
+                       return -EOPNOTSUPP;
+               }
+               if (reg2->type != PTR_TO_STACK) {
+                       pr_info("map_lookup: unsupported key ptr type %d\n",
+                               reg2->type);
+                       return -EOPNOTSUPP;
+               }
+               if (!tnum_is_const(reg2->var_off)) {
+                       pr_info("map_lookup: variable key pointer\n");
+                       return -EOPNOTSUPP;
+               }
+
+               off = reg2->var_off.value + reg2->off;
+               if (-off % 4) {
+                       pr_info("map_lookup: unaligned stack pointer %lld\n",
+                               -off);
+                       return -EOPNOTSUPP;
+               }
+
+               /* Rest of the checks is only if we re-parse the same insn */
+               if (!meta->func_id)
+                       break;
+
+               old_off = meta->arg2.var_off.value + meta->arg2.off;
+               meta->arg2_var_off |= off != old_off;
+
+               if (meta->arg1.map_ptr != reg1->map_ptr) {
+                       pr_info("map_lookup: called for different map\n");
+                       return -EOPNOTSUPP;
+               }
+               break;
        default:
                pr_warn("unsupported function id: %d\n", func_id);
                return -EOPNOTSUPP;
        }
 
+       meta->func_id = func_id;
+       meta->arg1 = *reg1;
        meta->arg2 = *reg2;
 
        return 0;
-- 
2.15.1

Reply via email to