/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(C) 2019 Marvell International Ltd.
 */

#include "otx2_ethdev.h"
#include "otx2_ethdev_sec.h"
#include "otx2_flow.h"

#define NPC_MAX_FIELD_NAME_SIZE 80
#define NPC_RX_ACTIONOP_MASK		GENMASK(3, 0)
#define NPC_RX_ACTION_PFFUNC_MASK	GENMASK(19, 4)
#define NPC_RX_ACTION_INDEX_MASK	GENMASK(39, 20)
#define NPC_RX_ACTION_MATCH_MASK	GENMASK(55, 40)
#define NPC_RX_ACTION_FLOWKEY_MASK	GENMASK(60, 56)

#define NPC_TX_ACTION_INDEX_MASK	GENMASK(31, 12)
#define NPC_TX_ACTION_MATCH_MASK	GENMASK(47, 32)

#define NIX_RX_VTAGACT_VTAG0_RELPTR_MASK	GENMASK(7, 0)
#define NIX_RX_VTAGACT_VTAG0_LID_MASK		GENMASK(10, 8)
#define NIX_RX_VTAGACT_VTAG0_TYPE_MASK		GENMASK(14, 12)
#define NIX_RX_VTAGACT_VTAG0_VALID_MASK		BIT_ULL(15)

#define NIX_RX_VTAGACT_VTAG1_RELPTR_MASK	GENMASK(39, 32)
#define NIX_RX_VTAGACT_VTAG1_LID_MASK		GENMASK(42, 40)
#define NIX_RX_VTAGACT_VTAG1_TYPE_MASK		GENMASK(46, 44)
#define NIX_RX_VTAGACT_VTAG1_VALID_MASK		BIT_ULL(47)

#define NIX_TX_VTAGACT_VTAG0_RELPTR_MASK	GENMASK(7, 0)
#define NIX_TX_VTAGACT_VTAG0_LID_MASK		GENMASK(10, 8)
#define NIX_TX_VTAGACT_VTAG0_OP_MASK		GENMASK(13, 12)
#define NIX_TX_VTAGACT_VTAG0_DEF_MASK		GENMASK(25, 16)

#define NIX_TX_VTAGACT_VTAG1_RELPTR_MASK	GENMASK(39, 32)
#define NIX_TX_VTAGACT_VTAG1_LID_MASK		GENMASK(42, 40)
#define NIX_TX_VTAGACT_VTAG1_OP_MASK		GENMASK(45, 44)
#define NIX_TX_VTAGACT_VTAG1_DEF_MASK		GENMASK(57, 48)

struct npc_rx_parse_nibble_s {
	uint16_t chan         : 3;
	uint16_t errlev       : 1;
	uint16_t errcode      : 2;
	uint16_t l2l3bm       : 1;
	uint16_t laflags      : 2;
	uint16_t latype       : 1;
	uint16_t lbflags      : 2;
	uint16_t lbtype       : 1;
	uint16_t lcflags      : 2;
	uint16_t lctype       : 1;
	uint16_t ldflags      : 2;
	uint16_t ldtype       : 1;
	uint16_t leflags      : 2;
	uint16_t letype       : 1;
	uint16_t lfflags      : 2;
	uint16_t lftype       : 1;
	uint16_t lgflags      : 2;
	uint16_t lgtype       : 1;
	uint16_t lhflags      : 2;
	uint16_t lhtype       : 1;
} __rte_packed;

const char *intf_str[] = {
	"NIX-RX",
	"NIX-TX",
};

const char *ltype_str[NPC_MAX_LID][NPC_MAX_LT] = {
	[NPC_LID_LA][0] = "NONE",
	[NPC_LID_LA][NPC_LT_LA_ETHER] = "LA_ETHER",
	[NPC_LID_LA][NPC_LT_LA_IH_NIX_ETHER] = "LA_IH_NIX_ETHER",
	[NPC_LID_LA][NPC_LT_LA_HIGIG2_ETHER] = "LA_HIGIG2_ETHER",
	[NPC_LID_LA][NPC_LT_LA_IH_NIX_HIGIG2_ETHER] = "LA_IH_NIX_HIGIG2_ETHER",
	[NPC_LID_LB][0] = "NONE",
	[NPC_LID_LB][NPC_LT_LB_CTAG] = "LB_CTAG",
	[NPC_LID_LB][NPC_LT_LB_STAG_QINQ] = "LB_STAG_QINQ",
	[NPC_LID_LB][NPC_LT_LB_ETAG] = "LB_ETAG",
	[NPC_LID_LB][NPC_LT_LB_EXDSA] = "LB_EXDSA",
	[NPC_LID_LB][NPC_LT_LB_VLAN_EXDSA] = "LB_VLAN_EXDSA",
	[NPC_LID_LC][0] = "NONE",
	[NPC_LID_LC][NPC_LT_LC_IP] = "LC_IP",
	[NPC_LID_LC][NPC_LT_LC_IP6] = "LC_IP6",
	[NPC_LID_LC][NPC_LT_LC_ARP] = "LC_ARP",
	[NPC_LID_LC][NPC_LT_LC_IP6_EXT] = "LC_IP6_EXT",
	[NPC_LID_LC][NPC_LT_LC_NGIO] = "LC_NGIO",
	[NPC_LID_LD][0] = "NONE",
	[NPC_LID_LD][NPC_LT_LD_ICMP] = "LD_ICMP",
	[NPC_LID_LD][NPC_LT_LD_ICMP6] = "LD_ICMP6",
	[NPC_LID_LD][NPC_LT_LD_UDP] = "LD_UDP",
	[NPC_LID_LD][NPC_LT_LD_TCP] = "LD_TCP",
	[NPC_LID_LD][NPC_LT_LD_SCTP] = "LD_SCTP",
	[NPC_LID_LD][NPC_LT_LD_GRE] = "LD_GRE",
	[NPC_LID_LD][NPC_LT_LD_NVGRE] = "LD_NVGRE",
	[NPC_LID_LE][0] = "NONE",
	[NPC_LID_LE][NPC_LT_LE_VXLAN] = "LE_VXLAN",
	[NPC_LID_LE][NPC_LT_LE_ESP] = "LE_ESP",
	[NPC_LID_LE][NPC_LT_LE_GTPC] = "LE_GTPC",
	[NPC_LID_LE][NPC_LT_LE_GTPU] = "LE_GTPU",
	[NPC_LID_LE][NPC_LT_LE_GENEVE] = "LE_GENEVE",
	[NPC_LID_LE][NPC_LT_LE_VXLANGPE] = "LE_VXLANGPE",
	[NPC_LID_LF][0] = "NONE",
	[NPC_LID_LF][NPC_LT_LF_TU_ETHER] = "LF_TU_ETHER",
	[NPC_LID_LG][0] = "NONE",
	[NPC_LID_LG][NPC_LT_LG_TU_IP] = "LG_TU_IP",
	[NPC_LID_LG][NPC_LT_LG_TU_IP6] = "LG_TU_IP6",
	[NPC_LID_LH][0] = "NONE",
	[NPC_LID_LH][NPC_LT_LH_TU_UDP] = "LH_TU_UDP",
	[NPC_LID_LH][NPC_LT_LH_TU_TCP] = "LH_TU_TCP",
	[NPC_LID_LH][NPC_LT_LH_TU_SCTP] = "LH_TU_SCTP",
	[NPC_LID_LH][NPC_LT_LH_TU_ESP] = "LH_TU_ESP",
};

static uint16_t
otx2_get_nibbles(struct rte_flow *flow, uint16_t size, uint32_t bit_offset)
{
	uint32_t byte_index, noffset;
	uint16_t data, mask;
	uint8_t *bytes;

	bytes = (uint8_t *)flow->mcam_data;
	mask = (1ULL << (size * 4)) - 1;
	byte_index = bit_offset / 8;
	noffset = bit_offset % 8;
	data = *(uint16_t *)&bytes[byte_index];
	data >>= noffset;
	data &= mask;

	return data;
}

static void
otx2_flow_print_parse_nibbles(FILE *file, struct rte_flow *flow,
			      uint64_t parse_nibbles)
{
	struct npc_rx_parse_nibble_s *rx_parse;
	uint32_t data, offset = 0;

	rx_parse = (struct npc_rx_parse_nibble_s *)&parse_nibbles;

	if (rx_parse->chan) {
		data = otx2_get_nibbles(flow, 3, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_CHAN:%#03X\n", data);
		offset += 12;
	}

	if (rx_parse->errlev) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_ERRLEV:%#X\n", data);
		offset += 4;
	}

	if (rx_parse->errcode) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_ERRCODE:%#02X\n", data);
		offset += 8;
	}

	if (rx_parse->l2l3bm) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_L2L3_BCAST:%#X\n", data);
		offset += 4;
	}

	if (rx_parse->latype) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LA_LTYPE:%s\n",
			ltype_str[NPC_LID_LA][data]);
		offset += 4;
	}

	if (rx_parse->laflags) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LA_FLAGS:%#02X\n", data);
		offset += 8;
	}

	if (rx_parse->lbtype) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LB_LTYPE:%s\n",
			ltype_str[NPC_LID_LB][data]);
		offset += 4;
	}

	if (rx_parse->lbflags) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LB_FLAGS:%#02X\n", data);
		offset += 8;
	}

	if (rx_parse->lctype) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LC_LTYPE:%s\n",
			ltype_str[NPC_LID_LC][data]);
		offset += 4;
	}

	if (rx_parse->lcflags) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LC_FLAGS:%#02X\n", data);
		offset += 8;
	}

	if (rx_parse->ldtype) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LD_LTYPE:%s\n",
			ltype_str[NPC_LID_LD][data]);
		offset += 4;
	}

	if (rx_parse->ldflags) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LD_FLAGS:%#02X\n", data);
		offset += 8;
	}

	if (rx_parse->letype) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LE_LTYPE:%s\n",
			ltype_str[NPC_LID_LE][data]);
		offset += 4;
	}

	if (rx_parse->leflags) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LE_FLAGS:%#02X\n", data);
		offset += 8;
	}

	if (rx_parse->lftype) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LF_LTYPE:%s\n",
			ltype_str[NPC_LID_LF][data]);
		offset += 4;
	}

	if (rx_parse->lfflags) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LF_FLAGS:%#02X\n", data);
		offset += 8;
	}

	if (rx_parse->lgtype) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LG_LTYPE:%s\n",
			ltype_str[NPC_LID_LG][data]);
		offset += 4;
	}

	if (rx_parse->lgflags) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LG_FLAGS:%#02X\n", data);
		offset += 8;
	}

	if (rx_parse->lhtype) {
		data = otx2_get_nibbles(flow, 1, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LH_LTYPE:%s\n",
			ltype_str[NPC_LID_LH][data]);
		offset += 4;
	}

	if (rx_parse->lhflags) {
		data = otx2_get_nibbles(flow, 2, offset);
		fprintf(file, "\tNPC_PARSE_NIBBLE_LH_FLAGS:%#02X\n", data);
	}
}

static void
otx2_flow_print_xtractinfo(FILE *file, struct npc_xtract_info *lfinfo,
			   struct rte_flow *flow, int lid, int lt)
{
	uint8_t *datastart, *maskstart;
	int i;

	datastart = (uint8_t *)&flow->mcam_data + lfinfo->key_off;
	maskstart = (uint8_t *)&flow->mcam_mask + lfinfo->key_off;

	fprintf(file, "\t%s, hdr offset:%#X, len:%#X, key offset:%#X, ",
		ltype_str[lid][lt], lfinfo->hdr_off,
		lfinfo->len, lfinfo->key_off);

	fprintf(file, "Data:0X");
	for (i = lfinfo->len - 1; i >= 0; i--)
		fprintf(file, "%02X", datastart[i]);

	fprintf(file, ", ");

	fprintf(file, "Mask:0X");

	for (i = lfinfo->len - 1; i >= 0; i--)
		fprintf(file, "%02X", maskstart[i]);

	fprintf(file, "\n");
}

static void
otx2_flow_print_item(FILE *file, struct otx2_eth_dev *hw,
		     struct npc_xtract_info *xinfo, struct rte_flow *flow,
		     int intf, int lid, int lt, int ld)
{
	struct otx2_npc_flow_info *npc_flow = &hw->npc_flow;
	struct npc_xtract_info *lflags_info;
	int i, lf_cfg;

	otx2_flow_print_xtractinfo(file, xinfo, flow, lid, lt);

	if (xinfo->flags_enable) {
		lf_cfg = npc_flow->prx_lfcfg[ld].i;

		if (lf_cfg == lid) {
			for (i = 0; i < NPC_MAX_LFL; i++) {
				lflags_info = npc_flow->prx_fxcfg[intf]
							[ld][i].xtract;

				otx2_flow_print_xtractinfo(file, lflags_info,
							   flow, lid, lt);
			}
		}
	}
}

static void
otx2_flow_dump_patterns(FILE *file, struct otx2_eth_dev *hw,
			struct rte_flow *flow)
{
	struct otx2_npc_flow_info *npc_flow = &hw->npc_flow;
	struct npc_lid_lt_xtract_info *lt_xinfo;
	struct npc_xtract_info *xinfo;
	uint32_t intf, lid, ld, i;
	uint64_t parse_nibbles;
	uint16_t ltype;

	intf = flow->nix_intf;
	parse_nibbles = npc_flow->keyx_supp_nmask[intf];
	otx2_flow_print_parse_nibbles(file, flow, parse_nibbles);

	for (i = 0; i < flow->num_patterns; i++) {
		lid = flow->dump_data[i].lid;
		ltype = flow->dump_data[i].ltype;
		lt_xinfo = &npc_flow->prx_dxcfg[intf][lid][ltype];

		for (ld = 0; ld < NPC_MAX_LD; ld++) {
			xinfo = &lt_xinfo->xtract[ld];
			if (!xinfo->enable)
				continue;
			otx2_flow_print_item(file, hw, xinfo, flow, intf, lid,
					     ltype, ld);
		}
	}
}

static void
otx2_flow_dump_tx_action(FILE *file, uint64_t npc_action)
{
	char index_name[NPC_MAX_FIELD_NAME_SIZE] = "Index:";
	uint32_t tx_op, index, match_id;

	tx_op = npc_action & NPC_RX_ACTIONOP_MASK;

	fprintf(file, "\tActionOp:");

	switch (tx_op) {
	case NIX_TX_ACTIONOP_DROP:
		fprintf(file, "NIX_TX_ACTIONOP_DROP (%lu)\n",
			(uint64_t)NIX_RX_ACTIONOP_DROP);
		break;
	case NIX_TX_ACTIONOP_UCAST_DEFAULT:
		fprintf(file, "NIX_TX_ACTIONOP_UCAST_DEFAULT (%lu)\n",
			(uint64_t)NIX_TX_ACTIONOP_UCAST_DEFAULT);
		break;
	case NIX_TX_ACTIONOP_UCAST_CHAN:
		fprintf(file, "NIX_TX_ACTIONOP_UCAST_DEFAULT (%lu)\n",
			(uint64_t)NIX_TX_ACTIONOP_UCAST_CHAN);
		strncpy(index_name, "Transmit Channel:",
			NPC_MAX_FIELD_NAME_SIZE);
		break;
	case NIX_TX_ACTIONOP_MCAST:
		fprintf(file, "NIX_TX_ACTIONOP_MCAST (%lu)\n",
			(uint64_t)NIX_TX_ACTIONOP_MCAST);
		strncpy(index_name, "Multicast Table Index:",
			NPC_MAX_FIELD_NAME_SIZE);
		break;
	case NIX_TX_ACTIONOP_DROP_VIOL:
		fprintf(file, "NIX_TX_ACTIONOP_DROP_VIOL (%lu)\n",
			(uint64_t)NIX_TX_ACTIONOP_DROP_VIOL);
		break;
	}

	index = ((npc_action & NPC_TX_ACTION_INDEX_MASK) >> 12) & 0xFFFFF;

	fprintf(file, "\t%s:%#05X\n", index_name, index);

	match_id = ((npc_action & NPC_TX_ACTION_MATCH_MASK) >> 32) & 0xFFFF;

	fprintf(file, "\tMatch Id:%#04X\n", match_id);
}

static void
otx2_flow_dump_rx_action(FILE *file, uint64_t npc_action)
{
	uint32_t rx_op, pf_func, index, match_id, flowkey_alg;
	char index_name[NPC_MAX_FIELD_NAME_SIZE] = "Index:";

	rx_op = npc_action & NPC_RX_ACTIONOP_MASK;

	fprintf(file, "\tActionOp:");

	switch (rx_op) {
	case NIX_RX_ACTIONOP_DROP:
		fprintf(file, "NIX_RX_ACTIONOP_DROP (%lu)\n",
			(uint64_t)NIX_RX_ACTIONOP_DROP);
		break;
	case NIX_RX_ACTIONOP_UCAST:
		fprintf(file, "NIX_RX_ACTIONOP_UCAST (%lu)\n",
			(uint64_t)NIX_RX_ACTIONOP_UCAST);
		strncpy(index_name, "RQ Index", NPC_MAX_FIELD_NAME_SIZE);
		break;
	case NIX_RX_ACTIONOP_UCAST_IPSEC:
		fprintf(file, "NIX_RX_ACTIONOP_UCAST_IPSEC (%lu)\n",
			(uint64_t)NIX_RX_ACTIONOP_UCAST_IPSEC);
		strncpy(index_name, "RQ Index:", NPC_MAX_FIELD_NAME_SIZE);
		break;
	case NIX_RX_ACTIONOP_MCAST:
		fprintf(file, "NIX_RX_ACTIONOP_MCAST (%lu)\n",
			(uint64_t)NIX_RX_ACTIONOP_MCAST);
		strncpy(index_name, "Multicast/mirror table index",
			NPC_MAX_FIELD_NAME_SIZE);
		break;
	case NIX_RX_ACTIONOP_RSS:
		fprintf(file, "NIX_RX_ACTIONOP_RSS (%lu)\n",
			(uint64_t)NIX_RX_ACTIONOP_RSS);
		strncpy(index_name, "RSS Group Index",
			NPC_MAX_FIELD_NAME_SIZE);
		break;
	case NIX_RX_ACTIONOP_PF_FUNC_DROP:
		fprintf(file, "NIX_RX_ACTIONOP_PF_FUNC_DROP (%lu)\n",
			(uint64_t)NIX_RX_ACTIONOP_PF_FUNC_DROP);
		break;
	case NIX_RX_ACTIONOP_MIRROR:
		fprintf(file, "NIX_RX_ACTIONOP_MIRROR (%lu)\n",
			(uint64_t)NIX_RX_ACTIONOP_MIRROR);
		strncpy(index_name, "Multicast/mirror table index",
			NPC_MAX_FIELD_NAME_SIZE);
		break;
	}

	pf_func = ((npc_action & NPC_RX_ACTION_PFFUNC_MASK) >> 4) & 0xFFFF;

	fprintf(file, "\tPF_FUNC: %#04X\n", pf_func);

	index = ((npc_action & NPC_RX_ACTION_INDEX_MASK) >> 20) & 0xFFFFF;

	fprintf(file, "\t%s:%#05X\n", index_name, index);

	match_id = ((npc_action & NPC_RX_ACTION_MATCH_MASK) >> 40) & 0xFFFF;

	fprintf(file, "\tMatch Id:%#04X\n", match_id);

	flowkey_alg = ((npc_action & NPC_RX_ACTION_FLOWKEY_MASK) >> 56) & 0x1F;

	fprintf(file, "\tFlow Key Alg:%#X\n", flowkey_alg);
}

static void
otx2_flow_dump_parsed_action(FILE *file, uint64_t npc_action, bool is_rx)
{
	if (is_rx) {
		fprintf(file, "NPC RX Action:%#016lX\n", npc_action);
		otx2_flow_dump_rx_action(file, npc_action);
	} else {
		fprintf(file, "NPC TX Action:%#016lX\n", npc_action);
		otx2_flow_dump_tx_action(file, npc_action);
	}
}

static void
otx2_flow_dump_rx_vtag_action(FILE *file, uint64_t vtag_action)
{
	uint32_t type, lid, relptr;

	if (vtag_action & NIX_RX_VTAGACT_VTAG0_VALID_MASK) {
		relptr = vtag_action & NIX_RX_VTAGACT_VTAG0_RELPTR_MASK;
		lid = ((vtag_action & NIX_RX_VTAGACT_VTAG0_LID_MASK) >> 8)
			& 0x7;
		type = ((vtag_action & NIX_RX_VTAGACT_VTAG0_TYPE_MASK) >> 12)
			& 0x7;

		fprintf(file, "\tVTAG0:relptr:%#X\n", relptr);
		fprintf(file, "\tlid:%#X\n", lid);
		fprintf(file, "\ttype:%#X\n", type);
	}

	if (vtag_action & NIX_RX_VTAGACT_VTAG1_VALID_MASK) {
		relptr = ((vtag_action & NIX_RX_VTAGACT_VTAG1_RELPTR_MASK)
			   >> 32) & 0xFF;
		lid = ((vtag_action & NIX_RX_VTAGACT_VTAG1_LID_MASK) >> 40)
			& 0x7;
		type = ((vtag_action & NIX_RX_VTAGACT_VTAG1_TYPE_MASK) >> 44)
			& 0x7;

		fprintf(file, "\tVTAG1:relptr:%#X\n", relptr);
		fprintf(file, "\tlid:%#X\n", lid);
		fprintf(file, "\ttype:%#X\n", type);
	}
}

static void
otx2_get_vtag_opname(uint32_t op, char *opname, int len)
{
	switch (op) {
	case 0x0:
		strncpy(opname, "NOP", len - 1);
		break;
	case 0x1:
		strncpy(opname, "INSERT", len - 1);
		break;
	case 0x2:
		strncpy(opname, "REPLACE", len - 1);
		break;
	}
}

static void
otx2_flow_dump_tx_vtag_action(FILE *file, uint64_t vtag_action)
{
	uint32_t relptr, lid, op, vtag_def;
	char opname[10];

	relptr = vtag_action & NIX_TX_VTAGACT_VTAG0_RELPTR_MASK;
	lid = ((vtag_action & NIX_TX_VTAGACT_VTAG0_LID_MASK) >> 8) & 0x7;
	op = ((vtag_action & NIX_TX_VTAGACT_VTAG0_OP_MASK) >> 12) & 0x3;
	vtag_def = ((vtag_action & NIX_TX_VTAGACT_VTAG0_DEF_MASK) >> 16)
		   & 0x3FF;

	otx2_get_vtag_opname(op, opname, sizeof(opname));

	fprintf(file, "\tVTAG0 relptr:%#X\n", relptr);
	fprintf(file, "\tlid:%#X\n", lid);
	fprintf(file, "\top:%s\n", opname);
	fprintf(file, "\tvtag_def:%#X\n", vtag_def);

	relptr = ((vtag_action & NIX_TX_VTAGACT_VTAG1_RELPTR_MASK) >> 32)
		 & 0xFF;
	lid = ((vtag_action & NIX_TX_VTAGACT_VTAG1_LID_MASK) >> 40) & 0x7;
	op = ((vtag_action & NIX_TX_VTAGACT_VTAG1_OP_MASK) >> 44) & 0x3;
	vtag_def = ((vtag_action & NIX_TX_VTAGACT_VTAG1_DEF_MASK) >> 48)
		   & 0x3FF;

	otx2_get_vtag_opname(op, opname, sizeof(opname));

	fprintf(file, "\tVTAG1:relptr:%#X\n", relptr);
	fprintf(file, "\tlid:%#X\n", lid);
	fprintf(file, "\top:%s\n", opname);
	fprintf(file, "\tvtag_def:%#X\n", vtag_def);
}

static void
otx2_flow_dump_vtag_action(FILE *file, uint64_t vtag_action, bool is_rx)
{
	if (is_rx) {
		fprintf(file, "NPC RX VTAG Action:%#016lX\n", vtag_action);
		otx2_flow_dump_rx_vtag_action(file, vtag_action);
	} else {
		fprintf(file, "NPC TX VTAG Action:%#016lX\n", vtag_action);
		otx2_flow_dump_tx_vtag_action(file, vtag_action);
	}
}

void
otx2_flow_dump(FILE *file, struct otx2_eth_dev *hw, struct rte_flow *flow)
{
	bool is_rx = 0;
	int i;

	fprintf(file, "MCAM Index:%d\n", flow->mcam_id);
	fprintf(file, "Interface :%s (%d)\n", intf_str[flow->nix_intf],
		flow->nix_intf);
	fprintf(file, "Priority  :%d\n", flow->priority);

	if (flow->nix_intf == NIX_INTF_RX)
		is_rx = 1;

	otx2_flow_dump_parsed_action(file, flow->npc_action, is_rx);
	otx2_flow_dump_vtag_action(file, flow->vtag_action, is_rx);
	fprintf(file, "Patterns:\n");
	otx2_flow_dump_patterns(file, hw, flow);

	fprintf(file, "MCAM Raw Data :\n");

	for (i = 0; i < OTX2_MAX_MCAM_WIDTH_DWORDS; i++)  {
		fprintf(file, "\tDW%d     :%016lX\n", i, flow->mcam_data[i]);
		fprintf(file, "\tDW%d_Mask:%016lX\n", i, flow->mcam_mask[i]);
	}

	fprintf(file, "\n");
}
