|
@@ -553,27 +553,51 @@ wrp_reg_subpart(struct nfp_prog *nfp_prog, swreg dst, swreg src, u8 field_len,
|
|
|
emit_ld_field_any(nfp_prog, dst, mask, src, sc, offset * 8, true);
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+addr40_offset(struct nfp_prog *nfp_prog, u8 src_gpr, swreg offset,
|
|
|
+ swreg *rega, swreg *regb)
|
|
|
+{
|
|
|
+ if (offset == reg_imm(0)) {
|
|
|
+ *rega = reg_a(src_gpr);
|
|
|
+ *regb = reg_b(src_gpr + 1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ emit_alu(nfp_prog, imm_a(nfp_prog), reg_a(src_gpr), ALU_OP_ADD, offset);
|
|
|
+ emit_alu(nfp_prog, imm_b(nfp_prog), reg_b(src_gpr + 1), ALU_OP_ADD_C,
|
|
|
+ reg_imm(0));
|
|
|
+ *rega = imm_a(nfp_prog);
|
|
|
+ *regb = imm_b(nfp_prog);
|
|
|
+}
|
|
|
+
|
|
|
/* NFP has Command Push Pull bus which supports bluk memory operations. */
|
|
|
static int nfp_cpp_memcpy(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
|
|
{
|
|
|
bool descending_seq = meta->ldst_gather_len < 0;
|
|
|
s16 len = abs(meta->ldst_gather_len);
|
|
|
swreg src_base, off;
|
|
|
+ bool src_40bit_addr;
|
|
|
unsigned int i;
|
|
|
u8 xfer_num;
|
|
|
|
|
|
off = re_load_imm_any(nfp_prog, meta->insn.off, imm_b(nfp_prog));
|
|
|
+ src_40bit_addr = meta->ptr.type == PTR_TO_MAP_VALUE;
|
|
|
src_base = reg_a(meta->insn.src_reg * 2);
|
|
|
xfer_num = round_up(len, 4) / 4;
|
|
|
|
|
|
+ if (src_40bit_addr)
|
|
|
+ addr40_offset(nfp_prog, meta->insn.src_reg, off, &src_base,
|
|
|
+ &off);
|
|
|
+
|
|
|
/* Setup PREV_ALU fields to override memory read length. */
|
|
|
if (len > 32)
|
|
|
wrp_immed(nfp_prog, reg_none(),
|
|
|
CMD_OVE_LEN | FIELD_PREP(CMD_OV_LEN, xfer_num - 1));
|
|
|
|
|
|
/* Memory read from source addr into transfer-in registers. */
|
|
|
- emit_cmd_any(nfp_prog, CMD_TGT_READ32_SWAP, CMD_MODE_32b, 0, src_base,
|
|
|
- off, xfer_num - 1, true, len > 32);
|
|
|
+ emit_cmd_any(nfp_prog, CMD_TGT_READ32_SWAP,
|
|
|
+ src_40bit_addr ? CMD_MODE_40b_BA : CMD_MODE_32b, 0,
|
|
|
+ src_base, off, xfer_num - 1, true, len > 32);
|
|
|
|
|
|
/* Move from transfer-in to transfer-out. */
|
|
|
for (i = 0; i < xfer_num; i++)
|
|
@@ -711,20 +735,20 @@ data_ld(struct nfp_prog *nfp_prog, swreg offset, u8 dst_gpr, int size)
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-data_ld_host_order(struct nfp_prog *nfp_prog, u8 src_gpr, swreg offset,
|
|
|
- u8 dst_gpr, int size)
|
|
|
+data_ld_host_order(struct nfp_prog *nfp_prog, u8 dst_gpr,
|
|
|
+ swreg lreg, swreg rreg, int size, enum cmd_mode mode)
|
|
|
{
|
|
|
unsigned int i;
|
|
|
u8 mask, sz;
|
|
|
|
|
|
- /* We load the value from the address indicated in @offset and then
|
|
|
+ /* We load the value from the address indicated in rreg + lreg and then
|
|
|
* mask out the data we don't need. Note: this is little endian!
|
|
|
*/
|
|
|
sz = max(size, 4);
|
|
|
mask = size < 4 ? GENMASK(size - 1, 0) : 0;
|
|
|
|
|
|
- emit_cmd(nfp_prog, CMD_TGT_READ32_SWAP, CMD_MODE_32b, 0,
|
|
|
- reg_a(src_gpr), offset, sz / 4 - 1, true);
|
|
|
+ emit_cmd(nfp_prog, CMD_TGT_READ32_SWAP, mode, 0,
|
|
|
+ lreg, rreg, sz / 4 - 1, true);
|
|
|
|
|
|
i = 0;
|
|
|
if (mask)
|
|
@@ -740,6 +764,26 @@ data_ld_host_order(struct nfp_prog *nfp_prog, u8 src_gpr, swreg offset,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+data_ld_host_order_addr32(struct nfp_prog *nfp_prog, u8 src_gpr, swreg offset,
|
|
|
+ u8 dst_gpr, u8 size)
|
|
|
+{
|
|
|
+ return data_ld_host_order(nfp_prog, dst_gpr, reg_a(src_gpr), offset,
|
|
|
+ size, CMD_MODE_32b);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+data_ld_host_order_addr40(struct nfp_prog *nfp_prog, u8 src_gpr, swreg offset,
|
|
|
+ u8 dst_gpr, u8 size)
|
|
|
+{
|
|
|
+ swreg rega, regb;
|
|
|
+
|
|
|
+ addr40_offset(nfp_prog, src_gpr, offset, ®a, ®b);
|
|
|
+
|
|
|
+ return data_ld_host_order(nfp_prog, dst_gpr, rega, regb,
|
|
|
+ size, CMD_MODE_40b_BA);
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
construct_data_ind_ld(struct nfp_prog *nfp_prog, u16 offset, u16 src, u8 size)
|
|
|
{
|
|
@@ -1778,8 +1822,20 @@ mem_ldx_data(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
|
|
|
|
|
tmp_reg = re_load_imm_any(nfp_prog, meta->insn.off, imm_b(nfp_prog));
|
|
|
|
|
|
- return data_ld_host_order(nfp_prog, meta->insn.src_reg * 2, tmp_reg,
|
|
|
- meta->insn.dst_reg * 2, size);
|
|
|
+ return data_ld_host_order_addr32(nfp_prog, meta->insn.src_reg * 2,
|
|
|
+ tmp_reg, meta->insn.dst_reg * 2, size);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+mem_ldx_emem(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
|
|
+ unsigned int size)
|
|
|
+{
|
|
|
+ swreg tmp_reg;
|
|
|
+
|
|
|
+ tmp_reg = re_load_imm_any(nfp_prog, meta->insn.off, imm_b(nfp_prog));
|
|
|
+
|
|
|
+ return data_ld_host_order_addr40(nfp_prog, meta->insn.src_reg * 2,
|
|
|
+ tmp_reg, meta->insn.dst_reg * 2, size);
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -1803,6 +1859,9 @@ mem_ldx(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
|
|
return mem_ldx_stack(nfp_prog, meta, size,
|
|
|
meta->ptr.off + meta->ptr.var_off.value);
|
|
|
|
|
|
+ if (meta->ptr.type == PTR_TO_MAP_VALUE)
|
|
|
+ return mem_ldx_emem(nfp_prog, meta, size);
|
|
|
+
|
|
|
return -EOPNOTSUPP;
|
|
|
}
|
|
|
|