diff mbox series

[net-next,1/4] net: microchip: vcap: Add vcap_get_rule

Message ID 20221130143525.934906-2-horatiu.vultur@microchip.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: lan966x: Enable PTP on bridge interfaces | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 2 this patch: 2
netdev/cc_maintainers success CCed 10 of 10 maintainers
netdev/build_clang success Errors and warnings before: 5 this patch: 5
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 2 this patch: 2
netdev/checkpatch warning WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Horatiu Vultur Nov. 30, 2022, 2:35 p.m. UTC
Add function vcap_get_rule which returns a rule based on the internal
rule id.
The entire functionality of reading and decoding the rule from the VCAP
was inside vcap_api_debugfs file. So move the entire implementation in
vcap_api as this is used also by vcap_get_rule.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../net/ethernet/microchip/vcap/vcap_api.c    | 772 ++++++++++++++++++
 .../ethernet/microchip/vcap/vcap_api_client.h |   2 +
 .../microchip/vcap/vcap_api_debugfs.c         | 492 ++---------
 .../microchip/vcap/vcap_api_private.h         |  14 +
 4 files changed, 848 insertions(+), 432 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index f2435d7ab515f..27128313f15f1 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -169,6 +169,227 @@  static void vcap_encode_typegroups(u32 *stream, int sw_width,
 	}
 }
 
+static bool vcap_bitarray_zero(int width, u8 *value)
+{
+	int bytes = DIV_ROUND_UP(width, BITS_PER_BYTE);
+	u8 total = 0, bmask = 0xff;
+	int rwidth = width;
+	int idx;
+
+	for (idx = 0; idx < bytes; ++idx, rwidth -= BITS_PER_BYTE) {
+		if (rwidth && rwidth < BITS_PER_BYTE)
+			bmask = (1 << rwidth) - 1;
+		total += value[idx] & bmask;
+	}
+	return total == 0;
+}
+
+static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr)
+{
+	u32 mask = BIT(itr->reg_bitpos);
+	u32 *p = &stream[itr->reg_idx];
+
+	return !!(*p & mask);
+}
+
+static void vcap_decode_field(u32 *stream, struct vcap_stream_iter *itr,
+			      int width, u8 *value)
+{
+	int idx;
+
+	/* Loop over the field value bits and get the field bits and
+	 * set them in the output value byte array
+	 */
+	for (idx = 0; idx < width; idx++) {
+		u8 bidx = idx & 0x7;
+
+		/* Decode one field value bit */
+		if (vcap_get_bit(stream, itr))
+			*value |= 1 << bidx;
+		vcap_iter_next(itr);
+		if (bidx == 7)
+			value++;
+	}
+}
+
+/* Verify that the type id in the stream matches the type id of the keyset */
+static bool vcap_verify_keystream_keyset(struct vcap_control *vctrl,
+					 enum vcap_type vt,
+					 u32 *keystream,
+					 u32 *mskstream,
+					 enum vcap_keyfield_set keyset)
+{
+	const struct vcap_info *vcap = &vctrl->vcaps[vt];
+	const struct vcap_field *typefld;
+	const struct vcap_typegroup *tgt;
+	const struct vcap_field *fields;
+	struct vcap_stream_iter iter;
+	const struct vcap_set *info;
+	u32 value = 0;
+	u32 mask = 0;
+
+	if (vcap_keyfield_count(vctrl, vt, keyset) == 0)
+		return false;
+
+	info = vcap_keyfieldset(vctrl, vt, keyset);
+	/* Check that the keyset is valid */
+	if (!info)
+		return false;
+
+	/* a type_id of value -1 means that there is no type field */
+	if (info->type_id == (u8)-1)
+		return true;
+
+	/* Get a valid typegroup for the specific keyset */
+	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
+	if (!tgt)
+		return false;
+
+	fields = vcap_keyfields(vctrl, vt, keyset);
+	if (!fields)
+		return false;
+
+	typefld = &fields[VCAP_KF_TYPE];
+	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
+	vcap_decode_field(mskstream, &iter, typefld->width, (u8 *)&mask);
+	/* no type info if there are no mask bits */
+	if (vcap_bitarray_zero(typefld->width, (u8 *)&mask))
+		return false;
+
+	/* Get the value of the type field in the stream and compare to the
+	 * one define in the vcap keyset
+	 */
+	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
+	vcap_decode_field(keystream, &iter, typefld->width, (u8 *)&value);
+
+	return (value & mask) == (info->type_id & mask);
+}
+
+/* Verify that the typegroup bits have the correct values */
+static int vcap_verify_typegroups(u32 *stream, int sw_width,
+				  const struct vcap_typegroup *tgt, bool mask,
+				  int sw_max)
+{
+	struct vcap_stream_iter iter;
+	int sw_cnt, idx;
+
+	vcap_iter_set(&iter, sw_width, tgt, 0);
+	sw_cnt = 0;
+	while (iter.tg->width) {
+		u32 value = 0;
+		u32 tg_value = iter.tg->value;
+
+		if (mask)
+			tg_value = (1 << iter.tg->width) - 1;
+		/* Set position to current typegroup bit */
+		iter.offset = iter.tg->offset;
+		vcap_iter_update(&iter);
+		for (idx = 0; idx < iter.tg->width; idx++) {
+			/* Decode one typegroup bit */
+			if (vcap_get_bit(stream, &iter))
+				value |= 1 << idx;
+			iter.offset++;
+			vcap_iter_update(&iter);
+		}
+		if (value != tg_value)
+			return -EINVAL;
+		iter.tg++; /* next typegroup */
+		sw_cnt++;
+		/* Stop checking more typegroups */
+		if (sw_max && sw_cnt >= sw_max)
+			break;
+	}
+	return 0;
+}
+
+/* Find the subword width of the key typegroup that matches the stream data */
+static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl,
+					    enum vcap_type vt, u32 *stream,
+					    bool mask, int sw_max)
+{
+	const struct vcap_typegroup **tgt;
+	int sw_idx, res;
+
+	tgt = vctrl->vcaps[vt].keyfield_set_typegroups;
+	/* Try the longest subword match first */
+	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
+		if (!tgt[sw_idx])
+			continue;
+
+		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width,
+					     tgt[sw_idx], mask, sw_max);
+		if (res == 0)
+			return sw_idx;
+	}
+	return -EINVAL;
+}
+
+/* Verify that the typegroup information, subword count, keyset and type id
+ * are in sync and correct, return the list of matchin keysets
+ */
+int
+vcap_find_keystream_keysets(struct vcap_control *vctrl,
+			    enum vcap_type vt,
+			    u32 *keystream,
+			    u32 *mskstream,
+			    bool mask, int sw_max,
+			    struct vcap_keyset_list *kslist)
+{
+	const struct vcap_set *keyfield_set;
+	int sw_count, idx;
+
+	sw_count = vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask,
+						    sw_max);
+	if (sw_count < 0)
+		return sw_count;
+
+	keyfield_set = vctrl->vcaps[vt].keyfield_set;
+	for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
+		if (keyfield_set[idx].sw_per_item != sw_count)
+			continue;
+
+		if (vcap_verify_keystream_keyset(vctrl, vt, keystream,
+						 mskstream, idx))
+			vcap_keyset_list_add(kslist, idx);
+	}
+	if (kslist->cnt > 0)
+		return 0;
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(vcap_find_keystream_keysets);
+
+/* Read key data from a VCAP address and discover if there are any rule keysets
+ * here
+ */
+int vcap_addr_keysets(struct vcap_control *vctrl,
+		      struct net_device *ndev,
+		      struct vcap_admin *admin,
+		      int addr,
+		      struct vcap_keyset_list *kslist)
+{
+	enum vcap_type vt = admin->vtype;
+	int keyset_sw_regs, idx;
+	u32 key = 0, mask = 0;
+
+	/* Read the cache at the specified address */
+	keyset_sw_regs = DIV_ROUND_UP(vctrl->vcaps[vt].sw_width, 32);
+	vctrl->ops->update(ndev, admin, VCAP_CMD_READ, VCAP_SEL_ALL, addr);
+	vctrl->ops->cache_read(ndev, admin, VCAP_SEL_ENTRY, 0,
+			       keyset_sw_regs);
+	/* Skip uninitialized key/mask entries */
+	for (idx = 0; idx < keyset_sw_regs; ++idx) {
+		key |= ~admin->cache.keystream[idx];
+		mask |= admin->cache.maskstream[idx];
+	}
+	if (key == 0 && mask == 0)
+		return -EINVAL;
+	/* Decode and locate the keysets */
+	return vcap_find_keystream_keysets(vctrl, vt, admin->cache.keystream,
+					   admin->cache.maskstream, false, 0,
+					   kslist);
+}
+EXPORT_SYMBOL_GPL(vcap_addr_keysets);
+
 /* Return the list of keyfields for the keyset */
 const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
 					enum vcap_type vt,
@@ -618,6 +839,517 @@  struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri)
 	return duprule;
 }
 
+static void vcap_apply_width(u8 *dst, int width, int bytes)
+{
+	u8 bmask;
+	int idx;
+
+	for (idx = 0; idx < bytes; idx++) {
+		if (width > 0)
+			if (width < 8)
+				bmask = (1 << width) - 1;
+			else
+				bmask = ~0;
+		else
+			bmask = 0;
+		dst[idx] &= bmask;
+		width -= 8;
+	}
+}
+
+static void vcap_copy_from_w32be(u8 *dst, u8 *src, int size, int width)
+{
+	int idx, ridx, wstart, nidx;
+	int tail_bytes = (((size + 4) >> 2) << 2) - size;
+
+	for (idx = 0, ridx = size - 1; idx < size; ++idx, --ridx) {
+		wstart = (idx >> 2) << 2;
+		nidx = wstart + 3 - (idx & 0x3);
+		if (nidx >= size)
+			nidx -= tail_bytes;
+		dst[nidx] = src[ridx];
+	}
+
+	vcap_apply_width(dst, width, size);
+}
+
+static void vcap_copy_action_bit_field(struct vcap_u1_action *field, u8 *value)
+{
+	field->value = (*value) & 0x1;
+}
+
+static void vcap_copy_limited_actionfield(u8 *dstvalue, u8 *srcvalue,
+					  int width, int bytes)
+{
+	memcpy(dstvalue, srcvalue, bytes);
+	vcap_apply_width(dstvalue, width, bytes);
+}
+
+static void vcap_copy_to_client_actionfield(struct vcap_rule_internal *ri,
+					    struct vcap_client_actionfield *field,
+					    u8 *value, u16 width)
+{
+	int field_size = actionfield_size_table[field->ctrl.type];
+
+	if (ri->admin->w32be) {
+		switch (field->ctrl.type) {
+		case VCAP_FIELD_BIT:
+			vcap_copy_action_bit_field(&field->data.u1, value);
+			break;
+		case VCAP_FIELD_U32:
+			vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
+						      value,
+						      width, field_size);
+			break;
+		case VCAP_FIELD_U48:
+			vcap_copy_from_w32be(field->data.u48.value, value,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U56:
+			vcap_copy_from_w32be(field->data.u56.value, value,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U64:
+			vcap_copy_from_w32be(field->data.u64.value, value,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U72:
+			vcap_copy_from_w32be(field->data.u72.value, value,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U112:
+			vcap_copy_from_w32be(field->data.u112.value, value,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U128:
+			vcap_copy_from_w32be(field->data.u128.value, value,
+					     field_size, width);
+			break;
+		};
+	} else {
+		switch (field->ctrl.type) {
+		case VCAP_FIELD_BIT:
+			vcap_copy_action_bit_field(&field->data.u1, value);
+			break;
+		case VCAP_FIELD_U32:
+			vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
+						      value,
+						      width, field_size);
+			break;
+		case VCAP_FIELD_U48:
+			vcap_copy_limited_actionfield(field->data.u48.value,
+						      value,
+						      width, field_size);
+			break;
+		case VCAP_FIELD_U56:
+			vcap_copy_limited_actionfield(field->data.u56.value,
+						      value,
+						      width, field_size);
+			break;
+		case VCAP_FIELD_U64:
+			vcap_copy_limited_actionfield(field->data.u64.value,
+						      value,
+						      width, field_size);
+			break;
+		case VCAP_FIELD_U72:
+			vcap_copy_limited_actionfield(field->data.u72.value,
+						      value,
+						      width, field_size);
+			break;
+		case VCAP_FIELD_U112:
+			vcap_copy_limited_actionfield(field->data.u112.value,
+						      value,
+						      width, field_size);
+			break;
+		case VCAP_FIELD_U128:
+			vcap_copy_limited_actionfield(field->data.u128.value,
+						      value,
+						      width, field_size);
+			break;
+		};
+	}
+}
+
+static void vcap_copy_key_bit_field(struct vcap_u1_key *field,
+				    u8 *value, u8 *mask)
+{
+	field->value = (*value) & 0x1;
+	field->mask = (*mask) & 0x1;
+}
+
+static void vcap_copy_limited_keyfield(u8 *dstvalue, u8 *dstmask,
+				       u8 *srcvalue, u8 *srcmask,
+				       int width, int bytes)
+{
+	memcpy(dstvalue, srcvalue, bytes);
+	vcap_apply_width(dstvalue, width, bytes);
+	memcpy(dstmask, srcmask, bytes);
+	vcap_apply_width(dstmask, width, bytes);
+}
+
+static void vcap_copy_to_client_keyfield(struct vcap_rule_internal *ri,
+					 struct vcap_client_keyfield *field,
+					 u8 *value, u8 *mask, u16 width)
+{
+	int field_size = keyfield_size_table[field->ctrl.type] / 2;
+
+	if (ri->admin->w32be) {
+		switch (field->ctrl.type) {
+		case VCAP_FIELD_BIT:
+			vcap_copy_key_bit_field(&field->data.u1, value, mask);
+			break;
+		case VCAP_FIELD_U32:
+			vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
+						   (u8 *)&field->data.u32.mask,
+						   value, mask,
+						   width, field_size);
+			break;
+		case VCAP_FIELD_U48:
+			vcap_copy_from_w32be(field->data.u48.value, value,
+					     field_size, width);
+			vcap_copy_from_w32be(field->data.u48.mask,  mask,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U56:
+			vcap_copy_from_w32be(field->data.u56.value, value,
+					     field_size, width);
+			vcap_copy_from_w32be(field->data.u56.mask,  mask,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U64:
+			vcap_copy_from_w32be(field->data.u64.value, value,
+					     field_size, width);
+			vcap_copy_from_w32be(field->data.u64.mask,  mask,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U72:
+			vcap_copy_from_w32be(field->data.u72.value, value,
+					     field_size, width);
+			vcap_copy_from_w32be(field->data.u72.mask,  mask,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U112:
+			vcap_copy_from_w32be(field->data.u112.value, value,
+					     field_size, width);
+			vcap_copy_from_w32be(field->data.u112.mask,  mask,
+					     field_size, width);
+			break;
+		case VCAP_FIELD_U128:
+			vcap_copy_from_w32be(field->data.u128.value, value,
+					     field_size, width);
+			vcap_copy_from_w32be(field->data.u128.mask,  mask,
+					     field_size, width);
+			break;
+		};
+	} else {
+		switch (field->ctrl.type) {
+		case VCAP_FIELD_BIT:
+			vcap_copy_key_bit_field(&field->data.u1, value, mask);
+			break;
+		case VCAP_FIELD_U32:
+			vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
+						   (u8 *)&field->data.u32.mask,
+						   value, mask,
+						   width, field_size);
+			break;
+		case VCAP_FIELD_U48:
+			vcap_copy_limited_keyfield(field->data.u48.value,
+						   field->data.u48.mask,
+						   value, mask,
+						   width, field_size);
+			break;
+		case VCAP_FIELD_U56:
+			vcap_copy_limited_keyfield(field->data.u56.value,
+						   field->data.u56.mask,
+						   value, mask,
+						   width, field_size);
+			break;
+		case VCAP_FIELD_U64:
+			vcap_copy_limited_keyfield(field->data.u64.value,
+						   field->data.u64.mask,
+						   value, mask,
+						   width, field_size);
+			break;
+		case VCAP_FIELD_U72:
+			vcap_copy_limited_keyfield(field->data.u72.value,
+						   field->data.u72.mask,
+						   value, mask,
+						   width, field_size);
+			break;
+		case VCAP_FIELD_U112:
+			vcap_copy_limited_keyfield(field->data.u112.value,
+						   field->data.u112.mask,
+						   value, mask,
+						   width, field_size);
+			break;
+		case VCAP_FIELD_U128:
+			vcap_copy_limited_keyfield(field->data.u128.value,
+						   field->data.u128.mask,
+						   value, mask,
+						   width, field_size);
+			break;
+		};
+	}
+}
+
+static void vcap_rule_alloc_keyfield(struct vcap_rule_internal *ri,
+				     const struct vcap_field *keyfield,
+				     enum vcap_key_field key,
+				     u8 *value, u8 *mask)
+{
+	struct vcap_client_keyfield *field;
+
+	field = kzalloc(sizeof(*field), GFP_KERNEL);
+	if (!field)
+		return;
+	INIT_LIST_HEAD(&field->ctrl.list);
+	field->ctrl.key = key;
+	field->ctrl.type = keyfield->type;
+	vcap_copy_to_client_keyfield(ri, field, value, mask, keyfield->width);
+	list_add_tail(&field->ctrl.list, &ri->data.keyfields);
+}
+
+/* Read key data from a VCAP address and discover if there is a rule keyset
+ * here
+ */
+static bool
+vcap_verify_actionstream_actionset(struct vcap_control *vctrl,
+				   enum vcap_type vt,
+				   u32 *actionstream,
+				   enum vcap_actionfield_set actionset)
+{
+	const struct vcap_typegroup *tgt;
+	const struct vcap_field *fields;
+	const struct vcap_set *info;
+
+	if (vcap_actionfield_count(vctrl, vt, actionset) == 0)
+		return false;
+
+	info = vcap_actionfieldset(vctrl, vt, actionset);
+	/* Check that the actionset is valid */
+	if (!info)
+		return false;
+
+	/* a type_id of value -1 means that there is no type field */
+	if (info->type_id == (u8)-1)
+		return true;
+
+	/* Get a valid typegroup for the specific actionset */
+	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
+	if (!tgt)
+		return false;
+
+	fields = vcap_actionfields(vctrl, vt, actionset);
+	if (!fields)
+		return false;
+
+	/* Later this will be expanded with a check of the type id */
+	return true;
+}
+
+/* Find the subword width of the action typegroup that matches the stream data
+ */
+static int vcap_find_actionstream_typegroup_sw(struct vcap_control *vctrl,
+					       enum vcap_type vt, u32 *stream,
+					       int sw_max)
+{
+	const struct vcap_typegroup **tgt;
+	int sw_idx, res;
+
+	tgt = vctrl->vcaps[vt].actionfield_set_typegroups;
+	/* Try the longest subword match first */
+	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
+		if (!tgt[sw_idx])
+			continue;
+		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width,
+					     tgt[sw_idx], false, sw_max);
+		if (res == 0)
+			return sw_idx;
+	}
+	return -EINVAL;
+}
+
+/* Verify that the typegroup information, subword count, actionset and type id
+ * are in sync and correct, return the actionset
+ */
+static enum vcap_actionfield_set
+vcap_find_actionstream_actionset(struct vcap_control *vctrl,
+				 enum vcap_type vt,
+				 u32 *stream,
+				 int sw_max)
+{
+	const struct vcap_set *actionfield_set;
+	int sw_count, idx;
+	bool res;
+
+	sw_count = vcap_find_actionstream_typegroup_sw(vctrl, vt, stream,
+						       sw_max);
+	if (sw_count < 0)
+		return sw_count;
+
+	actionfield_set = vctrl->vcaps[vt].actionfield_set;
+	for (idx = 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) {
+		if (actionfield_set[idx].sw_per_item != sw_count)
+			continue;
+
+		res = vcap_verify_actionstream_actionset(vctrl, vt,
+							 stream, idx);
+		if (res)
+			return idx;
+	}
+	return -EINVAL;
+}
+
+/* Store action value in an element in a list for the client */
+static void vcap_rule_alloc_actionfield(struct vcap_rule_internal *ri,
+					const struct vcap_field *actionfield,
+					enum vcap_action_field action,
+					u8 *value)
+{
+	struct vcap_client_actionfield *field;
+
+	field = kzalloc(sizeof(*field), GFP_KERNEL);
+	if (!field)
+		return;
+	INIT_LIST_HEAD(&field->ctrl.list);
+	field->ctrl.action = action;
+	field->ctrl.type = actionfield->type;
+	vcap_copy_to_client_actionfield(ri, field, value, actionfield->width);
+	list_add_tail(&field->ctrl.list, &ri->data.actionfields);
+}
+
+static int vcap_decode_actionset(struct vcap_rule_internal *ri)
+{
+	struct vcap_control *vctrl = ri->vctrl;
+	struct vcap_admin *admin = ri->admin;
+	const struct vcap_field *actionfield;
+	enum vcap_actionfield_set actionset;
+	enum vcap_type vt = admin->vtype;
+	const struct vcap_typegroup *tgt;
+	struct vcap_stream_iter iter;
+	int idx, res, actfield_count;
+	u32 *actstream;
+	u8 value[16];
+
+	actstream = admin->cache.actionstream;
+	res = vcap_find_actionstream_actionset(vctrl, vt, actstream, 0);
+	if (res < 0) {
+		pr_err("%s:%d: could not find valid actionset: %d\n",
+		       __func__, __LINE__, res);
+		return -EINVAL;
+	}
+	actionset = res;
+	actfield_count = vcap_actionfield_count(vctrl, vt, actionset);
+	actionfield = vcap_actionfields(vctrl, vt, actionset);
+	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
+	/* Start decoding the stream */
+	for (idx = 0; idx < actfield_count; ++idx) {
+		if (actionfield[idx].width <= 0)
+			continue;
+		/* Get the action */
+		memset(value, 0, DIV_ROUND_UP(actionfield[idx].width, 8));
+		vcap_iter_init(&iter, vctrl->vcaps[vt].act_width, tgt,
+			       actionfield[idx].offset);
+		vcap_decode_field(actstream, &iter, actionfield[idx].width,
+				  value);
+		/* Skip if no bits are set */
+		if (vcap_bitarray_zero(actionfield[idx].width, value))
+			continue;
+		vcap_rule_alloc_actionfield(ri, &actionfield[idx], idx, value);
+		/* Later the action id will also be checked */
+	}
+	return vcap_set_rule_set_actionset((struct vcap_rule *)ri, actionset);
+}
+
+static int vcap_decode_keyset(struct vcap_rule_internal *ri)
+{
+	struct vcap_control *vctrl = ri->vctrl;
+	struct vcap_stream_iter kiter, miter;
+	struct vcap_admin *admin = ri->admin;
+	enum vcap_keyfield_set keysets[10];
+	const struct vcap_field *keyfield;
+	enum vcap_type vt = admin->vtype;
+	const struct vcap_typegroup *tgt;
+	struct vcap_keyset_list matches;
+	enum vcap_keyfield_set keyset;
+	int idx, res, keyfield_count;
+	u32 *maskstream;
+	u32 *keystream;
+	u8 value[16];
+	u8 mask[16];
+
+	keystream = admin->cache.keystream;
+	maskstream = admin->cache.maskstream;
+	matches.keysets = keysets;
+	matches.cnt = 0;
+	matches.max = ARRAY_SIZE(keysets);
+	res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream,
+					  false, 0, &matches);
+	if (res < 0) {
+		pr_err("%s:%d: could not find valid keysets: %d\n",
+		       __func__, __LINE__, res);
+		return -EINVAL;
+	}
+	keyset = matches.keysets[0];
+	keyfield_count = vcap_keyfield_count(vctrl, vt, keyset);
+	keyfield = vcap_keyfields(vctrl, vt, keyset);
+	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
+	/* Start decoding the streams */
+	for (idx = 0; idx < keyfield_count; ++idx) {
+		if (keyfield[idx].width <= 0)
+			continue;
+		/* First get the mask */
+		memset(mask, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
+		vcap_iter_init(&miter, vctrl->vcaps[vt].sw_width, tgt,
+			       keyfield[idx].offset);
+		vcap_decode_field(maskstream, &miter, keyfield[idx].width,
+				  mask);
+		/* Skip if no mask bits are set */
+		if (vcap_bitarray_zero(keyfield[idx].width, mask))
+			continue;
+		/* Get the key */
+		memset(value, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
+		vcap_iter_init(&kiter, vctrl->vcaps[vt].sw_width, tgt,
+			       keyfield[idx].offset);
+		vcap_decode_field(keystream, &kiter, keyfield[idx].width,
+				  value);
+		vcap_rule_alloc_keyfield(ri, &keyfield[idx], idx, value, mask);
+	}
+	return vcap_set_rule_set_keyset((struct vcap_rule *)ri, keyset);
+}
+
+/* Read VCAP content into the VCAP cache */
+static int vcap_read_rule(struct vcap_rule_internal *ri)
+{
+	struct vcap_admin *admin = ri->admin;
+	int sw_idx, ent_idx = 0, act_idx = 0;
+	u32 addr = ri->addr;
+
+	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
+		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	vcap_erase_cache(ri);
+	/* Use the values in the streams to read the VCAP cache */
+	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
+		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ,
+				       VCAP_SEL_ALL, addr);
+		ri->vctrl->ops->cache_read(ri->ndev, admin,
+					   VCAP_SEL_ENTRY, ent_idx,
+					   ri->keyset_sw_regs);
+		ri->vctrl->ops->cache_read(ri->ndev, admin,
+					   VCAP_SEL_ACTION, act_idx,
+					   ri->actionset_sw_regs);
+		if (sw_idx == 0)
+			ri->vctrl->ops->cache_read(ri->ndev, admin,
+						   VCAP_SEL_COUNTER,
+						   ri->counter_id, 0);
+		ent_idx += ri->keyset_sw_regs;
+		act_idx += ri->actionset_sw_regs;
+	}
+	return 0;
+}
+
 /* Write VCAP cache content to the VCAP HW instance */
 static int vcap_write_rule(struct vcap_rule_internal *ri)
 {
@@ -1183,6 +1915,46 @@  void vcap_free_rule(struct vcap_rule *rule)
 }
 EXPORT_SYMBOL_GPL(vcap_free_rule);
 
+struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id)
+{
+	struct vcap_rule_internal *elem;
+	struct vcap_rule_internal *ri;
+	int err;
+
+	ri = NULL;
+
+	err = vcap_api_check(vctrl);
+	if (err)
+		return ERR_PTR(err);
+	elem = vcap_lookup_rule(vctrl, id);
+	if (!elem)
+		return NULL;
+	mutex_lock(&elem->admin->lock);
+	ri = vcap_dup_rule(elem);
+	if (IS_ERR(ri))
+		goto unlock;
+	err = vcap_read_rule(ri);
+	if (err) {
+		ri = ERR_PTR(err);
+		goto unlock;
+	}
+	err = vcap_decode_keyset(ri);
+	if (err) {
+		ri = ERR_PTR(err);
+		goto unlock;
+	}
+	err = vcap_decode_actionset(ri);
+	if (err) {
+		ri = ERR_PTR(err);
+		goto unlock;
+	}
+
+unlock:
+	mutex_unlock(&elem->admin->lock);
+	return (struct vcap_rule *)ri;
+}
+EXPORT_SYMBOL_GPL(vcap_get_rule);
+
 /* Return the alignment offset for a new rule address */
 static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
 {
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
index 93a0fcb12a819..a354dcd741e22 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
@@ -170,6 +170,8 @@  int vcap_add_rule(struct vcap_rule *rule);
 int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id);
 /* Make a full copy of an existing rule with a new rule id */
 struct vcap_rule *vcap_copy_rule(struct vcap_rule *rule);
+/* Get rule from a VCAP instance */
+struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id);
 
 /* Update the keyset for the rule */
 int vcap_set_rule_set_keyset(struct vcap_rule *rule,
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c
index 5df00e9403338..8c635d1e77b92 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c
@@ -18,355 +18,15 @@  struct vcap_port_debugfs_info {
 	struct net_device *ndev;
 };
 
-static bool vcap_bitarray_zero(int width, u8 *value)
-{
-	int bytes = DIV_ROUND_UP(width, BITS_PER_BYTE);
-	u8 total = 0, bmask = 0xff;
-	int rwidth = width;
-	int idx;
-
-	for (idx = 0; idx < bytes; ++idx, rwidth -= BITS_PER_BYTE) {
-		if (rwidth && rwidth < BITS_PER_BYTE)
-			bmask = (1 << rwidth) - 1;
-		total += value[idx] & bmask;
-	}
-	return total == 0;
-}
-
-static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr)
-{
-	u32 mask = BIT(itr->reg_bitpos);
-	u32 *p = &stream[itr->reg_idx];
-
-	return !!(*p & mask);
-}
-
-static void vcap_decode_field(u32 *stream, struct vcap_stream_iter *itr,
-			      int width, u8 *value)
-{
-	int idx;
-
-	/* Loop over the field value bits and get the field bits and
-	 * set them in the output value byte array
-	 */
-	for (idx = 0; idx < width; idx++) {
-		u8 bidx = idx & 0x7;
-
-		/* Decode one field value bit */
-		if (vcap_get_bit(stream, itr))
-			*value |= 1 << bidx;
-		vcap_iter_next(itr);
-		if (bidx == 7)
-			value++;
-	}
-}
-
-/* Verify that the typegroup bits have the correct values */
-static int vcap_verify_typegroups(u32 *stream, int sw_width,
-				  const struct vcap_typegroup *tgt, bool mask,
-				  int sw_max)
-{
-	struct vcap_stream_iter iter;
-	int sw_cnt, idx;
-
-	vcap_iter_set(&iter, sw_width, tgt, 0);
-	sw_cnt = 0;
-	while (iter.tg->width) {
-		u32 value = 0;
-		u32 tg_value = iter.tg->value;
-
-		if (mask)
-			tg_value = (1 << iter.tg->width) - 1;
-		/* Set position to current typegroup bit */
-		iter.offset = iter.tg->offset;
-		vcap_iter_update(&iter);
-		for (idx = 0; idx < iter.tg->width; idx++) {
-			/* Decode one typegroup bit */
-			if (vcap_get_bit(stream, &iter))
-				value |= 1 << idx;
-			iter.offset++;
-			vcap_iter_update(&iter);
-		}
-		if (value != tg_value)
-			return -EINVAL;
-		iter.tg++; /* next typegroup */
-		sw_cnt++;
-		/* Stop checking more typegroups */
-		if (sw_max && sw_cnt >= sw_max)
-			break;
-	}
-	return 0;
-}
-
-/* Find the subword width of the key typegroup that matches the stream data */
-static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl,
-					    enum vcap_type vt, u32 *stream,
-					    bool mask, int sw_max)
-{
-	const struct vcap_typegroup **tgt;
-	int sw_idx, res;
-
-	tgt = vctrl->vcaps[vt].keyfield_set_typegroups;
-	/* Try the longest subword match first */
-	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
-		if (!tgt[sw_idx])
-			continue;
-
-		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width,
-					     tgt[sw_idx], mask, sw_max);
-		if (res == 0)
-			return sw_idx;
-	}
-	return -EINVAL;
-}
-
-/* Find the subword width of the action typegroup that matches the stream data
- */
-static int vcap_find_actionstream_typegroup_sw(struct vcap_control *vctrl,
-					       enum vcap_type vt, u32 *stream,
-					       int sw_max)
-{
-	const struct vcap_typegroup **tgt;
-	int sw_idx, res;
-
-	tgt = vctrl->vcaps[vt].actionfield_set_typegroups;
-	/* Try the longest subword match first */
-	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
-		if (!tgt[sw_idx])
-			continue;
-		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width,
-					     tgt[sw_idx], false, sw_max);
-		if (res == 0)
-			return sw_idx;
-	}
-	return -EINVAL;
-}
-
-/* Verify that the type id in the stream matches the type id of the keyset */
-static bool vcap_verify_keystream_keyset(struct vcap_control *vctrl,
-					 enum vcap_type vt,
-					 u32 *keystream,
-					 u32 *mskstream,
-					 enum vcap_keyfield_set keyset)
-{
-	const struct vcap_info *vcap = &vctrl->vcaps[vt];
-	const struct vcap_field *typefld;
-	const struct vcap_typegroup *tgt;
-	const struct vcap_field *fields;
-	struct vcap_stream_iter iter;
-	const struct vcap_set *info;
-	u32 value = 0;
-	u32 mask = 0;
-
-	if (vcap_keyfield_count(vctrl, vt, keyset) == 0)
-		return false;
-
-	info = vcap_keyfieldset(vctrl, vt, keyset);
-	/* Check that the keyset is valid */
-	if (!info)
-		return false;
-
-	/* a type_id of value -1 means that there is no type field */
-	if (info->type_id == (u8)-1)
-		return true;
-
-	/* Get a valid typegroup for the specific keyset */
-	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
-	if (!tgt)
-		return false;
-
-	fields = vcap_keyfields(vctrl, vt, keyset);
-	if (!fields)
-		return false;
-
-	typefld = &fields[VCAP_KF_TYPE];
-	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
-	vcap_decode_field(mskstream, &iter, typefld->width, (u8 *)&mask);
-	/* no type info if there are no mask bits */
-	if (vcap_bitarray_zero(typefld->width, (u8 *)&mask))
-		return false;
-
-	/* Get the value of the type field in the stream and compare to the
-	 * one define in the vcap keyset
-	 */
-	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
-	vcap_decode_field(keystream, &iter, typefld->width, (u8 *)&value);
-
-	return (value & mask) == (info->type_id & mask);
-}
-
-/* Verify that the typegroup information, subword count, keyset and type id
- * are in sync and correct, return the list of matching keysets
- */
-static int
-vcap_find_keystream_keysets(struct vcap_control *vctrl,
-			    enum vcap_type vt,
-			    u32 *keystream,
-			    u32 *mskstream,
-			    bool mask, int sw_max,
-			    struct vcap_keyset_list *kslist)
-{
-	const struct vcap_set *keyfield_set;
-	int sw_count, idx;
-
-	sw_count = vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask,
-						    sw_max);
-	if (sw_count < 0)
-		return sw_count;
-
-	keyfield_set = vctrl->vcaps[vt].keyfield_set;
-	for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
-		if (keyfield_set[idx].sw_per_item != sw_count)
-			continue;
-
-		if (vcap_verify_keystream_keyset(vctrl, vt, keystream,
-						 mskstream, idx))
-			vcap_keyset_list_add(kslist, idx);
-	}
-	if (kslist->cnt > 0)
-		return 0;
-	return -EINVAL;
-}
-
-/* Read key data from a VCAP address and discover if there is a rule keyset
- * here
- */
-static bool
-vcap_verify_actionstream_actionset(struct vcap_control *vctrl,
-				   enum vcap_type vt,
-				   u32 *actionstream,
-				   enum vcap_actionfield_set actionset)
-{
-	const struct vcap_typegroup *tgt;
-	const struct vcap_field *fields;
-	const struct vcap_set *info;
-
-	if (vcap_actionfield_count(vctrl, vt, actionset) == 0)
-		return false;
-
-	info = vcap_actionfieldset(vctrl, vt, actionset);
-	/* Check that the actionset is valid */
-	if (!info)
-		return false;
-
-	/* a type_id of value -1 means that there is no type field */
-	if (info->type_id == (u8)-1)
-		return true;
-
-	/* Get a valid typegroup for the specific actionset */
-	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
-	if (!tgt)
-		return false;
-
-	fields = vcap_actionfields(vctrl, vt, actionset);
-	if (!fields)
-		return false;
-
-	/* Later this will be expanded with a check of the type id */
-	return true;
-}
-
-/* Verify that the typegroup information, subword count, actionset and type id
- * are in sync and correct, return the actionset
- */
-static enum vcap_actionfield_set
-vcap_find_actionstream_actionset(struct vcap_control *vctrl,
-				 enum vcap_type vt,
-				 u32 *stream,
-				 int sw_max)
-{
-	const struct vcap_set *actionfield_set;
-	int sw_count, idx;
-	bool res;
-
-	sw_count = vcap_find_actionstream_typegroup_sw(vctrl, vt, stream,
-						       sw_max);
-	if (sw_count < 0)
-		return sw_count;
-
-	actionfield_set = vctrl->vcaps[vt].actionfield_set;
-	for (idx = 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) {
-		if (actionfield_set[idx].sw_per_item != sw_count)
-			continue;
-
-		res = vcap_verify_actionstream_actionset(vctrl, vt,
-							 stream, idx);
-		if (res)
-			return idx;
-	}
-	return -EINVAL;
-}
-
-/* Read key data from a VCAP address and discover if there are any rule keysets
- * here
- */
-static int vcap_addr_keysets(struct vcap_control *vctrl,
-			     struct net_device *ndev,
-			     struct vcap_admin *admin,
-			     int addr,
-			     struct vcap_keyset_list *kslist)
-{
-	enum vcap_type vt = admin->vtype;
-	int keyset_sw_regs, idx;
-	u32 key = 0, mask = 0;
-
-	/* Read the cache at the specified address */
-	keyset_sw_regs = DIV_ROUND_UP(vctrl->vcaps[vt].sw_width, 32);
-	vctrl->ops->update(ndev, admin, VCAP_CMD_READ, VCAP_SEL_ALL, addr);
-	vctrl->ops->cache_read(ndev, admin, VCAP_SEL_ENTRY, 0,
-			       keyset_sw_regs);
-	/* Skip uninitialized key/mask entries */
-	for (idx = 0; idx < keyset_sw_regs; ++idx) {
-		key |= ~admin->cache.keystream[idx];
-		mask |= admin->cache.maskstream[idx];
-	}
-	if (key == 0 && mask == 0)
-		return -EINVAL;
-	/* Decode and locate the keysets */
-	return vcap_find_keystream_keysets(vctrl, vt, admin->cache.keystream,
-					   admin->cache.maskstream, false, 0,
-					   kslist);
-}
-
-static int vcap_read_rule(struct vcap_rule_internal *ri)
-{
-	struct vcap_admin *admin = ri->admin;
-	int sw_idx, ent_idx = 0, act_idx = 0;
-	u32 addr = ri->addr;
-
-	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
-		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
-		return -EINVAL;
-	}
-	vcap_erase_cache(ri);
-	/* Use the values in the streams to read the VCAP cache */
-	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
-		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ,
-				       VCAP_SEL_ALL, addr);
-		ri->vctrl->ops->cache_read(ri->ndev, admin,
-					   VCAP_SEL_ENTRY, ent_idx,
-					   ri->keyset_sw_regs);
-		ri->vctrl->ops->cache_read(ri->ndev, admin,
-					   VCAP_SEL_ACTION, act_idx,
-					   ri->actionset_sw_regs);
-		if (sw_idx == 0)
-			ri->vctrl->ops->cache_read(ri->ndev, admin,
-						   VCAP_SEL_COUNTER,
-						   ri->counter_id, 0);
-		ent_idx += ri->keyset_sw_regs;
-		act_idx += ri->actionset_sw_regs;
-	}
-	return 0;
-}
-
 /* Dump the keyfields value and mask values */
 static void vcap_debugfs_show_rule_keyfield(struct vcap_control *vctrl,
 					    struct vcap_output_print *out,
 					    enum vcap_key_field key,
 					    const struct vcap_field *keyfield,
-					    u8 *value, u8 *mask)
+					    struct vcap_client_keyfield_data *data)
 {
 	bool hex = false;
+	u8 *value, *mask;
 	int idx, bytes;
 
 	out->prf(out->dst, "    %s: W%d: ", vcap_keyfield_name(vctrl, key),
@@ -374,40 +34,62 @@  static void vcap_debugfs_show_rule_keyfield(struct vcap_control *vctrl,
 
 	switch (keyfield[key].type) {
 	case VCAP_FIELD_BIT:
-		out->prf(out->dst, "%d/%d", value[0], mask[0]);
+		out->prf(out->dst, "%d/%d", data->u1.value, data->u1.mask);
 		break;
 	case VCAP_FIELD_U32:
+		value = (u8 *)(&data->u32.value);
+		mask = (u8 *)(&data->u32.mask);
+
 		if (key == VCAP_KF_L3_IP4_SIP || key == VCAP_KF_L3_IP4_DIP) {
-			out->prf(out->dst, "%pI4h/%pI4h", value, mask);
+			out->prf(out->dst, "%pI4h/%pI4h", &data->u32.value,
+				 &data->u32.mask);
 		} else if (key == VCAP_KF_ETYPE ||
 			   key == VCAP_KF_IF_IGR_PORT_MASK) {
 			hex = true;
 		} else {
 			u32 fmsk = (1 << keyfield[key].width) - 1;
-			u32 val = *(u32 *)value;
-			u32 msk = *(u32 *)mask;
 
-			out->prf(out->dst, "%u/%u", val & fmsk, msk & fmsk);
+			out->prf(out->dst, "%u/%u", data->u32.value & fmsk,
+				 data->u32.mask & fmsk);
 		}
 		break;
 	case VCAP_FIELD_U48:
+		value = data->u48.value;
+		mask = data->u48.mask;
 		if (key == VCAP_KF_L2_SMAC || key == VCAP_KF_L2_DMAC)
-			out->prf(out->dst, "%pMR/%pMR", value, mask);
+			out->prf(out->dst, "%pMR/%pMR", data->u48.value,
+				 data->u48.mask);
 		else
 			hex = true;
 		break;
 	case VCAP_FIELD_U56:
+		value = data->u56.value;
+		mask = data->u56.mask;
+		hex = true;
+		break;
 	case VCAP_FIELD_U64:
+		value = data->u64.value;
+		mask = data->u64.mask;
+		hex = true;
+		break;
 	case VCAP_FIELD_U72:
+		value = data->u72.value;
+		mask = data->u72.mask;
+		hex = true;
+		break;
 	case VCAP_FIELD_U112:
+		value = data->u112.value;
+		mask = data->u112.mask;
 		hex = true;
 		break;
 	case VCAP_FIELD_U128:
 		if (key == VCAP_KF_L3_IP6_SIP || key == VCAP_KF_L3_IP6_DIP) {
 			u8 nvalue[16], nmask[16];
 
-			vcap_netbytes_copy(nvalue, value, sizeof(nvalue));
-			vcap_netbytes_copy(nmask, mask, sizeof(nmask));
+			vcap_netbytes_copy(nvalue, data->u128.value,
+					   sizeof(nvalue));
+			vcap_netbytes_copy(nmask, data->u128.mask,
+					   sizeof(nmask));
 			out->prf(out->dst, "%pI6/%pI6", nvalue, nmask);
 		} else {
 			hex = true;
@@ -472,19 +154,15 @@  static int vcap_debugfs_show_rule_keyset(struct vcap_rule_internal *ri,
 					 struct vcap_output_print *out)
 {
 	struct vcap_control *vctrl = ri->vctrl;
-	struct vcap_stream_iter kiter, miter;
 	struct vcap_admin *admin = ri->admin;
 	enum vcap_keyfield_set keysets[10];
 	const struct vcap_field *keyfield;
 	enum vcap_type vt = admin->vtype;
-	const struct vcap_typegroup *tgt;
+	struct vcap_client_keyfield *ckf;
 	struct vcap_keyset_list matches;
-	enum vcap_keyfield_set keyset;
-	int idx, res, keyfield_count;
 	u32 *maskstream;
 	u32 *keystream;
-	u8 value[16];
-	u8 mask[16];
+	int res;
 
 	keystream = admin->cache.keystream;
 	maskstream = admin->cache.maskstream;
@@ -498,39 +176,20 @@  static int vcap_debugfs_show_rule_keyset(struct vcap_rule_internal *ri,
 		       __func__, __LINE__, res);
 		return -EINVAL;
 	}
-	keyset = matches.keysets[0];
 	out->prf(out->dst, "  keysets:");
-	for (idx = 0; idx < matches.cnt; ++idx)
+	for (int idx = 0; idx < matches.cnt; ++idx)
 		out->prf(out->dst, " %s",
 			 vcap_keyset_name(vctrl, matches.keysets[idx]));
 	out->prf(out->dst, "\n");
 	out->prf(out->dst, "  keyset_sw: %d\n", ri->keyset_sw);
 	out->prf(out->dst, "  keyset_sw_regs: %d\n", ri->keyset_sw_regs);
-	keyfield_count = vcap_keyfield_count(vctrl, vt, keyset);
-	keyfield = vcap_keyfields(vctrl, vt, keyset);
-	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
-	/* Start decoding the streams */
-	for (idx = 0; idx < keyfield_count; ++idx) {
-		if (keyfield[idx].width <= 0)
-			continue;
-		/* First get the mask */
-		memset(mask, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
-		vcap_iter_init(&miter, vctrl->vcaps[vt].sw_width, tgt,
-			       keyfield[idx].offset);
-		vcap_decode_field(maskstream, &miter, keyfield[idx].width,
-				  mask);
-		/* Skip if no mask bits are set */
-		if (vcap_bitarray_zero(keyfield[idx].width, mask))
-			continue;
-		/* Get the key */
-		memset(value, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
-		vcap_iter_init(&kiter, vctrl->vcaps[vt].sw_width, tgt,
-			       keyfield[idx].offset);
-		vcap_decode_field(keystream, &kiter, keyfield[idx].width,
-				  value);
-		vcap_debugfs_show_rule_keyfield(vctrl, out, idx, keyfield,
-						value, mask);
+
+	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
+		keyfield = vcap_keyfields(vctrl, admin->vtype, ri->data.keyset);
+		vcap_debugfs_show_rule_keyfield(vctrl, out, ckf->ctrl.key,
+						keyfield, &ckf->data);
 	}
+
 	return 0;
 }
 
@@ -540,48 +199,21 @@  static int vcap_debugfs_show_rule_actionset(struct vcap_rule_internal *ri,
 	struct vcap_control *vctrl = ri->vctrl;
 	struct vcap_admin *admin = ri->admin;
 	const struct vcap_field *actionfield;
-	enum vcap_actionfield_set actionset;
-	enum vcap_type vt = admin->vtype;
-	const struct vcap_typegroup *tgt;
-	struct vcap_stream_iter iter;
-	int idx, res, actfield_count;
-	u32 *actstream;
-	u8 value[16];
-	bool no_bits;
-
-	actstream = admin->cache.actionstream;
-	res = vcap_find_actionstream_actionset(vctrl, vt, actstream, 0);
-	if (res < 0) {
-		pr_err("%s:%d: could not find valid actionset: %d\n",
-		       __func__, __LINE__, res);
-		return -EINVAL;
-	}
-	actionset = res;
+	struct vcap_client_actionfield *caf;
+
 	out->prf(out->dst, "  actionset: %s\n",
 		 vcap_actionset_name(vctrl, ri->data.actionset));
 	out->prf(out->dst, "  actionset_sw: %d\n", ri->actionset_sw);
 	out->prf(out->dst, "  actionset_sw_regs: %d\n", ri->actionset_sw_regs);
-	actfield_count = vcap_actionfield_count(vctrl, vt, actionset);
-	actionfield = vcap_actionfields(vctrl, vt, actionset);
-	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
-	/* Start decoding the stream */
-	for (idx = 0; idx < actfield_count; ++idx) {
-		if (actionfield[idx].width <= 0)
-			continue;
-		/* Get the action */
-		memset(value, 0, DIV_ROUND_UP(actionfield[idx].width, 8));
-		vcap_iter_init(&iter, vctrl->vcaps[vt].act_width, tgt,
-			       actionfield[idx].offset);
-		vcap_decode_field(actstream, &iter, actionfield[idx].width,
-				  value);
-		/* Skip if no bits are set */
-		no_bits = vcap_bitarray_zero(actionfield[idx].width, value);
-		if (no_bits)
-			continue;
-		/* Later the action id will also be checked */
-		vcap_debugfs_show_rule_actionfield(vctrl, out, idx, actionfield,
-						   value);
+
+	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
+		actionfield = vcap_actionfields(vctrl, admin->vtype,
+						ri->data.actionset);
+		vcap_debugfs_show_rule_actionfield(vctrl, out, caf->ctrl.action,
+						   actionfield,
+						   &caf->data.u1.value);
 	}
+
 	return 0;
 }
 
@@ -632,25 +264,21 @@  static int vcap_show_admin(struct vcap_control *vctrl,
 			   struct vcap_admin *admin,
 			   struct vcap_output_print *out)
 {
-	struct vcap_rule_internal *elem, *ri;
+	struct vcap_rule_internal *elem;
+	struct vcap_rule *vrule;
 	int ret = 0;
 
 	vcap_show_admin_info(vctrl, admin, out);
-	mutex_lock(&admin->lock);
 	list_for_each_entry(elem, &admin->rules, list) {
-		ri = vcap_dup_rule(elem);
-		if (IS_ERR(ri))
-			goto free_rule;
-		/* Read data from VCAP */
-		ret = vcap_read_rule(ri);
-		if (ret)
-			goto free_rule;
+		vrule = vcap_get_rule(vctrl, elem->data.id);
+		if (IS_ERR(vrule)) {
+			ret = PTR_ERR(vrule);
+			break;
+		}
 		out->prf(out->dst, "\n");
-		vcap_show_admin_rule(vctrl, admin, out, ri);
-free_rule:
-		vcap_free_rule((struct vcap_rule *)ri);
+		vcap_show_admin_rule(vctrl, admin, out, to_intrule(vrule));
+		vcap_free_rule(vrule);
 	}
-	mutex_unlock(&admin->lock);
 	return ret;
 }
 
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h
index 9ac1b1d55f22e..4fd21da976799 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h
@@ -96,4 +96,18 @@  const char *vcap_actionset_name(struct vcap_control *vctrl,
 const char *vcap_actionfield_name(struct vcap_control *vctrl,
 				  enum vcap_action_field action);
 
+/* Read key data from a VCAP address and discover if there are any rule keysets
+ * here
+ */
+int vcap_addr_keysets(struct vcap_control *vctrl, struct net_device *ndev,
+		      struct vcap_admin *admin, int addr,
+		      struct vcap_keyset_list *kslist);
+
+/* Verify that the typegroup information, subword count, keyset and type id
+ * are in sync and correct, return the list of matchin keysets
+ */
+int vcap_find_keystream_keysets(struct vcap_control *vctrl, enum vcap_type vt,
+				u32 *keystream, u32 *mskstream, bool mask,
+				int sw_max, struct vcap_keyset_list *kslist);
+
 #endif /* __VCAP_API_PRIVATE__ */