From nobody Thu Sep 18 18:52:36 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E5006C47088 for ; Sat, 3 Dec 2022 10:47:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229627AbiLCKrS (ORCPT ); Sat, 3 Dec 2022 05:47:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51368 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229775AbiLCKq7 (ORCPT ); Sat, 3 Dec 2022 05:46:59 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 565D28AAE5; Sat, 3 Dec 2022 02:46:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1670064406; x=1701600406; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=T2yHRLLHiDEXfzWpv1NBrm3qsVOvIBHRxvRYHIBbKqo=; b=Sdf89mlqH9mOTfUavE7aJcqYMgMLfZHkdWtWb8dEv8Qte6rVRGzEgEw3 btBIQ1fxu/V3kpmnc2FvdtDqh1iXKKwm6oxNxklq1ByFMHp8kdaEdpDGV be4JzSeIdDL6nGlNazg7F8/JCZQ3cq0WH8Uyu9o/1kA8sMslXnf3tTQpK owMdCaPAZW9lrqVSJteHtByH0KPUvGS6uh9C487pBqmKtVgIBGpRIzact TXmR3eZgQQfM42GhIEVFK4csiQBCckua8aWTvjggcrA5MZgcHflE4xNhg J8qAtUwPnnyKGwVn14r5zjCAyYzd3jJYg5oJPoORJEdrs4WqAXMLZGlfp w==; X-IronPort-AV: E=Sophos;i="5.96,214,1665471600"; d="scan'208";a="202447055" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 03 Dec 2022 03:46:35 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Sat, 3 Dec 2022 03:46:35 -0700 Received: from soft-dev3-1.microsemi.net (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Sat, 3 Dec 2022 03:46:32 -0700 From: Horatiu Vultur To: , , CC: , , , , , , , , , , Horatiu Vultur Subject: [PATCH net-next v3 1/4] net: microchip: vcap: Add vcap_get_rule Date: Sat, 3 Dec 2022 11:43:45 +0100 Message-ID: <20221203104348.1749811-2-horatiu.vultur@microchip.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221203104348.1749811-1-horatiu.vultur@microchip.com> References: <20221203104348.1749811-1-horatiu.vultur@microchip.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 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 --- .../net/ethernet/microchip/vcap/vcap_api.c | 772 ++++++++++++++++++ .../ethernet/microchip/vcap/vcap_api_client.h | 2 + .../microchip/vcap/vcap_api_debugfs.c | 498 ++--------- .../microchip/vcap/vcap_api_private.h | 14 + 4 files changed, 848 insertions(+), 438 deletions(-) diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/e= thernet/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 s= w_width, } } =20 +static bool vcap_bitarray_zero(int width, u8 *value) +{ + int bytes =3D DIV_ROUND_UP(width, BITS_PER_BYTE); + u8 total =3D 0, bmask =3D 0xff; + int rwidth =3D width; + int idx; + + for (idx =3D 0; idx < bytes; ++idx, rwidth -=3D BITS_PER_BYTE) { + if (rwidth && rwidth < BITS_PER_BYTE) + bmask =3D (1 << rwidth) - 1; + total +=3D value[idx] & bmask; + } + return total =3D=3D 0; +} + +static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr) +{ + u32 mask =3D BIT(itr->reg_bitpos); + u32 *p =3D &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 =3D 0; idx < width; idx++) { + u8 bidx =3D idx & 0x7; + + /* Decode one field value bit */ + if (vcap_get_bit(stream, itr)) + *value |=3D 1 << bidx; + vcap_iter_next(itr); + if (bidx =3D=3D 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 =3D &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 =3D 0; + u32 mask =3D 0; + + if (vcap_keyfield_count(vctrl, vt, keyset) =3D=3D 0) + return false; + + info =3D 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 =3D=3D (u8)-1) + return true; + + /* Get a valid typegroup for the specific keyset */ + tgt =3D vcap_keyfield_typegroup(vctrl, vt, keyset); + if (!tgt) + return false; + + fields =3D vcap_keyfields(vctrl, vt, keyset); + if (!fields) + return false; + + typefld =3D &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) =3D=3D (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 =3D 0; + while (iter.tg->width) { + u32 value =3D 0; + u32 tg_value =3D iter.tg->value; + + if (mask) + tg_value =3D (1 << iter.tg->width) - 1; + /* Set position to current typegroup bit */ + iter.offset =3D iter.tg->offset; + vcap_iter_update(&iter); + for (idx =3D 0; idx < iter.tg->width; idx++) { + /* Decode one typegroup bit */ + if (vcap_get_bit(stream, &iter)) + value |=3D 1 << idx; + iter.offset++; + vcap_iter_update(&iter); + } + if (value !=3D tg_value) + return -EINVAL; + iter.tg++; /* next typegroup */ + sw_cnt++; + /* Stop checking more typegroups */ + if (sw_max && sw_cnt >=3D sw_max) + break; + } + return 0; +} + +/* Find the subword width of the key typegroup that matches the stream dat= a */ +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 =3D vctrl->vcaps[vt].keyfield_set_typegroups; + /* Try the longest subword match first */ + for (sw_idx =3D vctrl->vcaps[vt].sw_count; sw_idx >=3D 0; sw_idx--) { + if (!tgt[sw_idx]) + continue; + + res =3D vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width, + tgt[sw_idx], mask, sw_max); + if (res =3D=3D 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 =3D vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask, + sw_max); + if (sw_count < 0) + return sw_count; + + keyfield_set =3D vctrl->vcaps[vt].keyfield_set; + for (idx =3D 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) { + if (keyfield_set[idx].sw_per_item !=3D 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 ke= ysets + * 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 =3D admin->vtype; + int keyset_sw_regs, idx; + u32 key =3D 0, mask =3D 0; + + /* Read the cache at the specified address */ + keyset_sw_regs =3D 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 =3D 0; idx < keyset_sw_regs; ++idx) { + key |=3D ~admin->cache.keystream[idx]; + mask |=3D admin->cache.maskstream[idx]; + } + if (key =3D=3D 0 && mask =3D=3D 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; } =20 +static void vcap_apply_width(u8 *dst, int width, int bytes) +{ + u8 bmask; + int idx; + + for (idx =3D 0; idx < bytes; idx++) { + if (width > 0) + if (width < 8) + bmask =3D (1 << width) - 1; + else + bmask =3D ~0; + else + bmask =3D 0; + dst[idx] &=3D bmask; + width -=3D 8; + } +} + +static void vcap_copy_from_w32be(u8 *dst, u8 *src, int size, int width) +{ + int idx, ridx, wstart, nidx; + int tail_bytes =3D (((size + 4) >> 2) << 2) - size; + + for (idx =3D 0, ridx =3D size - 1; idx < size; ++idx, --ridx) { + wstart =3D (idx >> 2) << 2; + nidx =3D wstart + 3 - (idx & 0x3); + if (nidx >=3D size) + nidx -=3D tail_bytes; + dst[nidx] =3D src[ridx]; + } + + vcap_apply_width(dst, width, size); +} + +static void vcap_copy_action_bit_field(struct vcap_u1_action *field, u8 *v= alue) +{ + field->value =3D (*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 =3D 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 =3D (*value) & 0x1; + field->mask =3D (*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 =3D 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 =3D kzalloc(sizeof(*field), GFP_KERNEL); + if (!field) + return; + INIT_LIST_HEAD(&field->ctrl.list); + field->ctrl.key =3D key; + field->ctrl.type =3D 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) =3D=3D 0) + return false; + + info =3D 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 =3D=3D (u8)-1) + return true; + + /* Get a valid typegroup for the specific actionset */ + tgt =3D vcap_actionfield_typegroup(vctrl, vt, actionset); + if (!tgt) + return false; + + fields =3D 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 =3D vctrl->vcaps[vt].actionfield_set_typegroups; + /* Try the longest subword match first */ + for (sw_idx =3D vctrl->vcaps[vt].sw_count; sw_idx >=3D 0; sw_idx--) { + if (!tgt[sw_idx]) + continue; + res =3D vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width, + tgt[sw_idx], false, sw_max); + if (res =3D=3D 0) + return sw_idx; + } + return -EINVAL; +} + +/* Verify that the typegroup information, subword count, actionset and typ= e 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 =3D vcap_find_actionstream_typegroup_sw(vctrl, vt, stream, + sw_max); + if (sw_count < 0) + return sw_count; + + actionfield_set =3D vctrl->vcaps[vt].actionfield_set; + for (idx =3D 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) { + if (actionfield_set[idx].sw_per_item !=3D sw_count) + continue; + + res =3D 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 =3D kzalloc(sizeof(*field), GFP_KERNEL); + if (!field) + return; + INIT_LIST_HEAD(&field->ctrl.list); + field->ctrl.action =3D action; + field->ctrl.type =3D 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 =3D ri->vctrl; + struct vcap_admin *admin =3D ri->admin; + const struct vcap_field *actionfield; + enum vcap_actionfield_set actionset; + enum vcap_type vt =3D admin->vtype; + const struct vcap_typegroup *tgt; + struct vcap_stream_iter iter; + int idx, res, actfield_count; + u32 *actstream; + u8 value[16]; + + actstream =3D admin->cache.actionstream; + res =3D 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 =3D res; + actfield_count =3D vcap_actionfield_count(vctrl, vt, actionset); + actionfield =3D vcap_actionfields(vctrl, vt, actionset); + tgt =3D vcap_actionfield_typegroup(vctrl, vt, actionset); + /* Start decoding the stream */ + for (idx =3D 0; idx < actfield_count; ++idx) { + if (actionfield[idx].width <=3D 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 =3D ri->vctrl; + struct vcap_stream_iter kiter, miter; + struct vcap_admin *admin =3D ri->admin; + enum vcap_keyfield_set keysets[10]; + const struct vcap_field *keyfield; + enum vcap_type vt =3D 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 =3D admin->cache.keystream; + maskstream =3D admin->cache.maskstream; + matches.keysets =3D keysets; + matches.cnt =3D 0; + matches.max =3D ARRAY_SIZE(keysets); + res =3D 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 =3D matches.keysets[0]; + keyfield_count =3D vcap_keyfield_count(vctrl, vt, keyset); + keyfield =3D vcap_keyfields(vctrl, vt, keyset); + tgt =3D vcap_keyfield_typegroup(vctrl, vt, keyset); + /* Start decoding the streams */ + for (idx =3D 0; idx < keyfield_count; ++idx) { + if (keyfield[idx].width <=3D 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 =3D ri->admin; + int sw_idx, ent_idx =3D 0, act_idx =3D 0; + u32 addr =3D 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 =3D 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 =3D=3D 0) + ri->vctrl->ops->cache_read(ri->ndev, admin, + VCAP_SEL_COUNTER, + ri->counter_id, 0); + ent_idx +=3D ri->keyset_sw_regs; + act_idx +=3D 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); =20 +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 =3D NULL; + + err =3D vcap_api_check(vctrl); + if (err) + return ERR_PTR(err); + elem =3D vcap_lookup_rule(vctrl, id); + if (!elem) + return NULL; + mutex_lock(&elem->admin->lock); + ri =3D vcap_dup_rule(elem); + if (IS_ERR(ri)) + goto unlock; + err =3D vcap_read_rule(ri); + if (err) { + ri =3D ERR_PTR(err); + goto unlock; + } + err =3D vcap_decode_keyset(ri); + if (err) { + ri =3D ERR_PTR(err); + goto unlock; + } + err =3D vcap_decode_actionset(ri); + if (err) { + ri =3D 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/driver= s/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); =20 /* 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/drive= rs/net/ethernet/microchip/vcap/vcap_api_debugfs.c index 3b8d165dc8322..895bfff550d23 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; }; =20 -static bool vcap_bitarray_zero(int width, u8 *value) -{ - int bytes =3D DIV_ROUND_UP(width, BITS_PER_BYTE); - u8 total =3D 0, bmask =3D 0xff; - int rwidth =3D width; - int idx; - - for (idx =3D 0; idx < bytes; ++idx, rwidth -=3D BITS_PER_BYTE) { - if (rwidth && rwidth < BITS_PER_BYTE) - bmask =3D (1 << rwidth) - 1; - total +=3D value[idx] & bmask; - } - return total =3D=3D 0; -} - -static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr) -{ - u32 mask =3D BIT(itr->reg_bitpos); - u32 *p =3D &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 =3D 0; idx < width; idx++) { - u8 bidx =3D idx & 0x7; - - /* Decode one field value bit */ - if (vcap_get_bit(stream, itr)) - *value |=3D 1 << bidx; - vcap_iter_next(itr); - if (bidx =3D=3D 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 =3D 0; - while (iter.tg->width) { - u32 value =3D 0; - u32 tg_value =3D iter.tg->value; - - if (mask) - tg_value =3D (1 << iter.tg->width) - 1; - /* Set position to current typegroup bit */ - iter.offset =3D iter.tg->offset; - vcap_iter_update(&iter); - for (idx =3D 0; idx < iter.tg->width; idx++) { - /* Decode one typegroup bit */ - if (vcap_get_bit(stream, &iter)) - value |=3D 1 << idx; - iter.offset++; - vcap_iter_update(&iter); - } - if (value !=3D tg_value) - return -EINVAL; - iter.tg++; /* next typegroup */ - sw_cnt++; - /* Stop checking more typegroups */ - if (sw_max && sw_cnt >=3D sw_max) - break; - } - return 0; -} - -/* Find the subword width of the key typegroup that matches the stream dat= a */ -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 =3D vctrl->vcaps[vt].keyfield_set_typegroups; - /* Try the longest subword match first */ - for (sw_idx =3D vctrl->vcaps[vt].sw_count; sw_idx >=3D 0; sw_idx--) { - if (!tgt[sw_idx]) - continue; - - res =3D vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width, - tgt[sw_idx], mask, sw_max); - if (res =3D=3D 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 =3D vctrl->vcaps[vt].actionfield_set_typegroups; - /* Try the longest subword match first */ - for (sw_idx =3D vctrl->vcaps[vt].sw_count; sw_idx >=3D 0; sw_idx--) { - if (!tgt[sw_idx]) - continue; - res =3D vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width, - tgt[sw_idx], false, sw_max); - if (res =3D=3D 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 =3D &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 =3D 0; - u32 mask =3D 0; - - if (vcap_keyfield_count(vctrl, vt, keyset) =3D=3D 0) - return false; - - info =3D 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 =3D=3D (u8)-1) - return true; - - /* Get a valid typegroup for the specific keyset */ - tgt =3D vcap_keyfield_typegroup(vctrl, vt, keyset); - if (!tgt) - return false; - - fields =3D vcap_keyfields(vctrl, vt, keyset); - if (!fields) - return false; - - typefld =3D &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) =3D=3D (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 =3D vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask, - sw_max); - if (sw_count < 0) - return sw_count; - - keyfield_set =3D vctrl->vcaps[vt].keyfield_set; - for (idx =3D 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) { - if (keyfield_set[idx].sw_per_item !=3D 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) =3D=3D 0) - return false; - - info =3D 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 =3D=3D (u8)-1) - return true; - - /* Get a valid typegroup for the specific actionset */ - tgt =3D vcap_actionfield_typegroup(vctrl, vt, actionset); - if (!tgt) - return false; - - fields =3D 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 typ= e 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 =3D vcap_find_actionstream_typegroup_sw(vctrl, vt, stream, - sw_max); - if (sw_count < 0) - return sw_count; - - actionfield_set =3D vctrl->vcaps[vt].actionfield_set; - for (idx =3D 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) { - if (actionfield_set[idx].sw_per_item !=3D sw_count) - continue; - - res =3D 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 ke= ysets - * 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 =3D admin->vtype; - int keyset_sw_regs, idx; - u32 key =3D 0, mask =3D 0; - - /* Read the cache at the specified address */ - keyset_sw_regs =3D 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 =3D 0; idx < keyset_sw_regs; ++idx) { - key |=3D ~admin->cache.keystream[idx]; - mask |=3D admin->cache.maskstream[idx]; - } - if (key =3D=3D 0 && mask =3D=3D 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 =3D ri->admin; - int sw_idx, ent_idx =3D 0, act_idx =3D 0; - u32 addr =3D 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 =3D 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 =3D=3D 0) - ri->vctrl->ops->cache_read(ri->ndev, admin, - VCAP_SEL_COUNTER, - ri->counter_id, 0); - ent_idx +=3D ri->keyset_sw_regs; - act_idx +=3D 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 =3D false; + u8 *value, *mask; int idx, bytes; =20 out->prf(out->dst, " %s: W%d: ", vcap_keyfield_name(vctrl, key), @@ -374,40 +34,62 @@ static void vcap_debugfs_show_rule_keyfield(struct vca= p_control *vctrl, =20 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 =3D (u8 *)(&data->u32.value); + mask =3D (u8 *)(&data->u32.mask); + if (key =3D=3D VCAP_KF_L3_IP4_SIP || key =3D=3D 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 =3D=3D VCAP_KF_ETYPE || key =3D=3D VCAP_KF_IF_IGR_PORT_MASK) { hex =3D true; } else { u32 fmsk =3D (1 << keyfield[key].width) - 1; - u32 val =3D *(u32 *)value; - u32 msk =3D *(u32 *)mask; =20 - 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 =3D data->u48.value; + mask =3D data->u48.mask; if (key =3D=3D VCAP_KF_L2_SMAC || key =3D=3D 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 =3D true; break; case VCAP_FIELD_U56: + value =3D data->u56.value; + mask =3D data->u56.mask; + hex =3D true; + break; case VCAP_FIELD_U64: + value =3D data->u64.value; + mask =3D data->u64.mask; + hex =3D true; + break; case VCAP_FIELD_U72: + value =3D data->u72.value; + mask =3D data->u72.mask; + hex =3D true; + break; case VCAP_FIELD_U112: + value =3D data->u112.value; + mask =3D data->u112.mask; hex =3D true; break; case VCAP_FIELD_U128: if (key =3D=3D VCAP_KF_L3_IP6_SIP || key =3D=3D VCAP_KF_L3_IP6_DIP) { u8 nvalue[16], nmask[16]; =20 - 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 =3D 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 =3D ri->vctrl; - struct vcap_stream_iter kiter, miter; struct vcap_admin *admin =3D ri->admin; enum vcap_keyfield_set keysets[10]; const struct vcap_field *keyfield; enum vcap_type vt =3D 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; =20 keystream =3D admin->cache.keystream; maskstream =3D 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 =3D matches.keysets[0]; out->prf(out->dst, " keysets:"); - for (idx =3D 0; idx < matches.cnt; ++idx) + for (int idx =3D 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 =3D vcap_keyfield_count(vctrl, vt, keyset); - keyfield =3D vcap_keyfields(vctrl, vt, keyset); - tgt =3D vcap_keyfield_typegroup(vctrl, vt, keyset); - /* Start decoding the streams */ - for (idx =3D 0; idx < keyfield_count; ++idx) { - if (keyfield[idx].width <=3D 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 =3D vcap_keyfields(vctrl, admin->vtype, ri->data.keyset); + vcap_debugfs_show_rule_keyfield(vctrl, out, ckf->ctrl.key, + keyfield, &ckf->data); } + return 0; } =20 @@ -540,48 +199,21 @@ static int vcap_debugfs_show_rule_actionset(struct vc= ap_rule_internal *ri, struct vcap_control *vctrl =3D ri->vctrl; struct vcap_admin *admin =3D ri->admin; const struct vcap_field *actionfield; - enum vcap_actionfield_set actionset; - enum vcap_type vt =3D 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 =3D admin->cache.actionstream; - res =3D 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 =3D 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 =3D vcap_actionfield_count(vctrl, vt, actionset); - actionfield =3D vcap_actionfields(vctrl, vt, actionset); - tgt =3D vcap_actionfield_typegroup(vctrl, vt, actionset); - /* Start decoding the stream */ - for (idx =3D 0; idx < actfield_count; ++idx) { - if (actionfield[idx].width <=3D 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 =3D 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 =3D 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; } =20 @@ -632,32 +264,22 @@ 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 =3D 0; =20 vcap_show_admin_info(vctrl, admin, out); - mutex_lock(&admin->lock); list_for_each_entry(elem, &admin->rules, list) { - ri =3D vcap_dup_rule(elem); - if (IS_ERR(ri)) { - ret =3D PTR_ERR(ri); - goto err_unlock; + vrule =3D vcap_get_rule(vctrl, elem->data.id); + if (IS_ERR_OR_NULL(vrule)) { + ret =3D PTR_ERR(vrule); + break; } - /* Read data from VCAP */ - ret =3D vcap_read_rule(ri); - if (ret) - goto err_free_rule; + out->prf(out->dst, "\n"); - vcap_show_admin_rule(vctrl, admin, out, ri); - 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 0; - -err_free_rule: - vcap_free_rule((struct vcap_rule *)ri); -err_unlock: - mutex_unlock(&admin->lock); return ret; } =20 diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h b/drive= rs/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 *vct= rl, const char *vcap_actionfield_name(struct vcap_control *vctrl, enum vcap_action_field action); =20 +/* Read key data from a VCAP address and discover if there are any rule ke= ysets + * 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__ */ --=20 2.38.0