+static int32_t ulp_mapper_field_buffer_eval(uint8_t *buffer, uint32_t bitlen,
+ uint64_t *output)
+{
+ uint16_t val_16;
+ uint32_t val_32;
+ uint64_t val_64;
+ uint32_t bytelen;
+
+ bytelen = ULP_BITS_2_BYTE(bitlen);
+ if (bytelen == sizeof(uint8_t)) {
+ *output = *((uint8_t *)buffer);
+ } else if (bytelen == sizeof(uint16_t)) {
+ val_16 = *((uint16_t *)buffer);
+ *output = tfp_be_to_cpu_16(val_16);
+ } else if (bytelen == sizeof(uint32_t)) {
+ val_32 = *((uint32_t *)buffer);
+ *output = tfp_be_to_cpu_32(val_32);
+ } else if (bytelen == sizeof(val_64)) {
+ val_64 = *((uint64_t *)buffer);
+ *output = tfp_be_to_cpu_64(val_64);
+ } else {
+ *output = 0;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int32_t ulp_mapper_field_blob_write(enum bnxt_ulp_field_src fld_src,
+ struct ulp_blob *blob,
+ uint8_t *val,
+ uint32_t val_len,
+ uint8_t **out_val)
+{
+ if (fld_src == BNXT_ULP_FIELD_SRC_ZERO) {
+ if (ulp_blob_pad_push(blob, val_len) < 0) {
+ BNXT_TF_DBG(ERR, "too large for blob\n");
+ return -EINVAL;
+ }
+ } else if (fld_src == BNXT_ULP_FIELD_SRC_ACT_PROP_SZ) {
+ if (ulp_blob_push_encap(blob, val, val_len) < 0) {
+ BNXT_TF_DBG(ERR, "encap blob push failed\n");
+ return -EINVAL;
+ }
+ } else if (fld_src == BNXT_ULP_FIELD_SRC_SKIP) {
+ /* do nothing */
+ } else {
+ if (!ulp_blob_push(blob, val, val_len)) {
+ BNXT_TF_DBG(ERR, "push of val1 failed\n");
+ return -EINVAL;
+ }
+ }
+ *out_val = val;
+ return 0;
+}
+
+static int32_t
+ulp_mapper_field_opc_process(struct bnxt_ulp_mapper_parms *parms,
+ enum tf_dir dir,
+ struct bnxt_ulp_mapper_field_info *fld,
+ struct ulp_blob *blob,
+ uint8_t is_key,
+ const char *name)
+{
+ uint16_t write_idx = blob->write_idx;
+ uint8_t *val = NULL, *val1, *val2, *val3;
+ uint32_t val_len = 0, val1_len = 0, val2_len = 0, val3_len = 0;
+ uint8_t process_src1 = 0, process_src2 = 0, process_src3 = 0;
+ uint8_t eval_src1 = 0, eval_src2 = 0, eval_src3 = 0;
+ uint64_t val_int = 0, val1_int = 0, val2_int = 0, val3_int = 0;
+ uint64_t value1 = 0, value2 = 0, value3 = 0;
+ int32_t rc = 0;
+
+ /* prepare the field source and values */
+ switch (fld->field_opc) {
+ case BNXT_ULP_FIELD_OPC_SRC1:
+ process_src1 = 1;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_THEN_SRC2_ELSE_SRC3:
+ process_src1 = 1;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_OR_SRC2_OR_SRC3:
+ case BNXT_ULP_FIELD_OPC_SRC1_AND_SRC2_OR_SRC3:
+ process_src3 = 1;
+ eval_src3 = 1;
+ process_src1 = 1;
+ process_src2 = 1;
+ eval_src1 = 1;
+ eval_src2 = 1;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_PLUS_SRC2:
+ case BNXT_ULP_FIELD_OPC_SRC1_MINUS_SRC2:
+ case BNXT_ULP_FIELD_OPC_SRC1_PLUS_SRC2_POST:
+ case BNXT_ULP_FIELD_OPC_SRC1_MINUS_SRC2_POST:
+ case BNXT_ULP_FIELD_OPC_SRC1_OR_SRC2:
+ case BNXT_ULP_FIELD_OPC_SRC1_AND_SRC2:
+ process_src1 = 1;
+ process_src2 = 1;
+ eval_src1 = 1;
+ eval_src2 = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* process the src1 opcode */
+ if (process_src1) {
+ if (ulp_mapper_field_src_process(parms, fld->field_src1,
+ fld->field_opr1, dir, is_key,
+ fld->field_bit_size, &val1,
+ &val1_len, &value1)) {
+ BNXT_TF_DBG(ERR, "fld src1 process failed\n");
+ goto error;
+ }
+ if (eval_src1) {
+ if (ulp_mapper_field_buffer_eval(val1, val1_len,
+ &val1_int)) {
+ BNXT_TF_DBG(ERR, "fld src1 eval failed\n");
+ goto error;
+ }
+ }
+ }
+
+ /* for "if then clause" set the correct process */
+ if (fld->field_opc == BNXT_ULP_FIELD_OPC_SRC1_THEN_SRC2_ELSE_SRC3) {
+ if (value1)
+ process_src2 = 1;
+ else
+ process_src3 = 1;
+ }
+
+ /* process src2 opcode */
+ if (process_src2) {
+ if (ulp_mapper_field_src_process(parms, fld->field_src2,
+ fld->field_opr2, dir, is_key,
+ fld->field_bit_size, &val2,
+ &val2_len, &value2)) {
+ BNXT_TF_DBG(ERR, "fld src2 process failed\n");
+ goto error;
+ }
+ if (eval_src2) {
+ if (ulp_mapper_field_buffer_eval(val2, val2_len,
+ &val2_int)) {
+ BNXT_TF_DBG(ERR, "fld src2 eval failed\n");
+ goto error;
+ }
+ }
+ }
+
+ /* process src3 opcode */
+ if (process_src3) {
+ if (ulp_mapper_field_src_process(parms, fld->field_src3,
+ fld->field_opr3, dir, is_key,
+ fld->field_bit_size, &val3,
+ &val3_len, &value3)) {
+ BNXT_TF_DBG(ERR, "fld src3 process failed\n");
+ goto error;
+ }
+ if (eval_src3) {
+ if (ulp_mapper_field_buffer_eval(val3, val3_len,
+ &val3_int)) {
+ BNXT_TF_DBG(ERR, "fld src3 eval failed\n");
+ goto error;
+ }
+ }
+ }
+
+ val_len = fld->field_bit_size;
+ /* process the field opcodes */
+ switch (fld->field_opc) {
+ case BNXT_ULP_FIELD_OPC_SRC1:
+ rc = ulp_mapper_field_blob_write(fld->field_src1,
+ blob, val1, val1_len, &val);
+ val_len = val1_len;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_THEN_SRC2_ELSE_SRC3:
+ if (value1) {
+ rc = ulp_mapper_field_blob_write(fld->field_src2, blob,
+ val2, val2_len, &val);
+ val_len = val2_len;
+ } else {
+ rc = ulp_mapper_field_blob_write(fld->field_src3, blob,
+ val3, val3_len, &val);
+ val_len = val3_len;
+ }
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_PLUS_SRC2:
+ case BNXT_ULP_FIELD_OPC_SRC1_PLUS_SRC2_POST:
+ val_int = val1_int + val2_int;
+ val_int = tfp_cpu_to_be_64(val_int);
+ val = ulp_blob_push_64(blob, &val_int, fld->field_bit_size);
+ if (!val)
+ rc = -EINVAL;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_MINUS_SRC2:
+ case BNXT_ULP_FIELD_OPC_SRC1_MINUS_SRC2_POST:
+ val_int = val1_int - val2_int;
+ val_int = tfp_cpu_to_be_64(val_int);
+ val = ulp_blob_push_64(blob, &val_int, fld->field_bit_size);
+ if (!val)
+ rc = -EINVAL;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_OR_SRC2:
+ val_int = val1_int | val2_int;
+ val_int = tfp_cpu_to_be_64(val_int);
+ val = ulp_blob_push_64(blob, &val_int, fld->field_bit_size);
+ if (!val)
+ rc = -EINVAL;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_OR_SRC2_OR_SRC3:
+ val_int = val1_int | val2_int | val3_int;
+ val_int = tfp_cpu_to_be_64(val_int);
+ val = ulp_blob_push_64(blob, &val_int, fld->field_bit_size);
+ if (!val)
+ rc = -EINVAL;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_AND_SRC2:
+ val_int = val1_int & val2_int;
+ val_int = tfp_cpu_to_be_64(val_int);
+ val = ulp_blob_push_64(blob, &val_int, fld->field_bit_size);
+ if (!val)
+ rc = -EINVAL;
+ break;
+ case BNXT_ULP_FIELD_OPC_SRC1_AND_SRC2_OR_SRC3:
+ val_int = val1_int & (val2_int | val3_int);
+ val_int = tfp_cpu_to_be_64(val_int);
+ val = ulp_blob_push_64(blob, &val_int, fld->field_bit_size);
+ if (!val)
+ rc = -EINVAL;
+ break;
+ case BNXT_ULP_FIELD_OPC_SKIP:
+ break;
+ default:
+ BNXT_TF_DBG(ERR, "Invalid fld opcode %u\n", fld->field_opc);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (!rc) {
+ return rc;
+ }
+error:
+ BNXT_TF_DBG(ERR, "Error in %s:%s process %u:%u\n", name,
+ fld->description, (val) ? write_idx : 0, val_len);
+ return -EINVAL;
+}
+