From nobody Mon Apr 13 20:06:42 2026 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 0E0A9C433FE for ; Wed, 16 Nov 2022 09:01:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238527AbiKPJA6 (ORCPT ); Wed, 16 Nov 2022 04:00:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54902 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238810AbiKPI7L (ORCPT ); Wed, 16 Nov 2022 03:59:11 -0500 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D5AA71B79E; Wed, 16 Nov 2022 00:58:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1668589106; x=1700125106; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=odCre0DHMmaMoYct33BAZyq+wFJy6LbxCi3tTtxryjg=; b=HMkuA6barBg2vXNHTLPg/tgIGTEx8MA2U/d+io26mKo0RPBOHw4VO2gq VOW8w/fK+8PHNf+NrqjloWAshJGmvNB7CEHzXmMWRA0tpRckJFea49kMF OoD1K5u6sDFolhmf3oNM73Wlv75hrZcsv3+xCGlO6gvNRru2IkQg3YLWe 0cippxzu1vd0WkscAG570JdP54+m+J1uRBN8vjnjqcaNJgcSVsZLcbchQ KUOcL1fNgjjomowI8VwXKrqJZ/mCoOr2wBqOXSnFnp2okQbET0vHfTp/y oNr3h68cR62vrlMyG5y1J7nfbqY+y+LqVdNiXsKNsAsd+Xj5AVhvPN43X A==; X-IronPort-AV: E=Sophos;i="5.96,167,1665471600"; d="scan'208";a="123662831" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa6.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 16 Nov 2022 01:58:23 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Wed, 16 Nov 2022 01:58:16 -0700 Received: from den-dk-m31857.microchip.com (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; Wed, 16 Nov 2022 01:58:13 -0700 From: Steen Hegelund To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni CC: Steen Hegelund , , Randy Dunlap , "Casper Andersson" , Russell King , Wan Jiabing , "Nathan Huckleberry" , , , , "Steen Hegelund" , Daniel Machon , Horatiu Vultur , Lars Povlsen Subject: [PATCH net-next 6/8] net: microchip: sparx5: Add VCAP debugFS key/action support for the VCAP API Date: Wed, 16 Nov 2022 09:57:45 +0100 Message-ID: <20221116085747.3810427-7-steen.hegelund@microchip.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221116085747.3810427-1-steen.hegelund@microchip.com> References: <20221116085747.3810427-1-steen.hegelund@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" This add support for displaying the keys and actions in a rule. The keys and action display format will be determined by the size and the type of the key or action. The longer keys will typically be displayed as a hexadecimal byte array. The actionset is not decoded in full as the Sparx5 IS2 only has one supported action, so this will be added later with other VCAP types. Signed-off-by: Steen Hegelund --- .../net/ethernet/microchip/vcap/vcap_api.c | 12 +- .../microchip/vcap/vcap_api_debugfs.c | 311 +++++++++++++++++- .../microchip/vcap/vcap_api_private.h | 16 + support | 1 + 4 files changed, 330 insertions(+), 10 deletions(-) create mode 160000 support diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/e= thernet/microchip/vcap/vcap_api.c index 3da714e9639c..3415605350c9 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -316,7 +316,7 @@ static int vcap_encode_rule_keyset(struct vcap_rule_int= ernal *ri) } =20 /* Return the list of actionfields for the actionset */ -static const struct vcap_field * +const struct vcap_field * vcap_actionfields(struct vcap_control *vctrl, enum vcap_type vt, enum vcap_actionfield_set actionset) { @@ -326,7 +326,7 @@ vcap_actionfields(struct vcap_control *vctrl, return vctrl->vcaps[vt].actionfield_set_map[actionset]; } =20 -static const struct vcap_set * +const struct vcap_set * vcap_actionfieldset(struct vcap_control *vctrl, enum vcap_type vt, enum vcap_actionfield_set actionset) { @@ -342,7 +342,7 @@ vcap_actionfieldset(struct vcap_control *vctrl, } =20 /* Return the typegroup table for the matching actionset (using subword si= ze) */ -static const struct vcap_typegroup * +const struct vcap_typegroup * vcap_actionfield_typegroup(struct vcap_control *vctrl, enum vcap_type vt, enum vcap_actionfield_set actionset) { @@ -355,9 +355,9 @@ vcap_actionfield_typegroup(struct vcap_control *vctrl, } =20 /* Return the number of actionfields in the actionset */ -static int vcap_actionfield_count(struct vcap_control *vctrl, - enum vcap_type vt, - enum vcap_actionfield_set actionset) +int vcap_actionfield_count(struct vcap_control *vctrl, + enum vcap_type vt, + enum vcap_actionfield_set actionset) { /* Check that the actionset exists in the vcap actionset list */ if (actionset >=3D vctrl->vcaps[vt].actionfield_set_size) diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c b/drive= rs/net/ethernet/microchip/vcap/vcap_api_debugfs.c index a2d66a36db1c..8e5b1cc24d80 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c @@ -120,6 +120,27 @@ static int vcap_find_keystream_typegroup_sw(struct vca= p_control *vctrl, return -EINVAL; } =20 +/* 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, @@ -205,6 +226,72 @@ vcap_keyfield_set vcap_find_keystream_keyset(struct vc= ap_control *vctrl, return -EINVAL; } =20 +/* Verify that the type id in the stream matches the type id of the action= set */ +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 is a rule keyse= t here */ static int vcap_addr_keyset(struct vcap_control *vctrl, struct net_device *ndev, @@ -263,6 +350,224 @@ static int vcap_read_rule(struct vcap_rule_internal *= ri) return 0; } =20 +/* 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) +{ + bool hex =3D false; + int idx, bytes; + + out->prf(out->dst, " %s: W%d: ", vcap_keyfield_name(vctrl, key), + keyfield[key].width); + + switch (keyfield[key].type) { + case VCAP_FIELD_BIT: + out->prf(out->dst, "%d/%d", value[0], mask[0]); + break; + case VCAP_FIELD_U32: + 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); + } 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; + + out->prf(out->dst, "%u/%u", val & fmsk, msk & fmsk); + } + break; + case VCAP_FIELD_U48: + if (key =3D=3D VCAP_KF_L2_SMAC || key =3D=3D VCAP_KF_L2_DMAC) + out->prf(out->dst, "%pMR/%pMR", value, mask); + else + hex =3D true; + break; + case VCAP_FIELD_U56: + case VCAP_FIELD_U64: + case VCAP_FIELD_U72: + case VCAP_FIELD_U112: + 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]; + + vcap_netbytes_copy(nvalue, value, sizeof(nvalue)); + vcap_netbytes_copy(nmask, mask, sizeof(nmask)); + out->prf(out->dst, "%pI6/%pI6", nvalue, nmask); + } else { + hex =3D true; + } + break; + } + if (hex) { + bytes =3D DIV_ROUND_UP(keyfield[key].width, BITS_PER_BYTE); + out->prf(out->dst, "0x"); + for (idx =3D 0; idx < bytes; ++idx) + out->prf(out->dst, "%02x", value[bytes - idx - 1]); + out->prf(out->dst, "/0x"); + for (idx =3D 0; idx < bytes; ++idx) + out->prf(out->dst, "%02x", mask[bytes - idx - 1]); + } + out->prf(out->dst, "\n"); +} + +static void +vcap_debugfs_show_rule_actionfield(struct vcap_control *vctrl, + struct vcap_output_print *out, + enum vcap_action_field action, + const struct vcap_field *actionfield, + u8 *value) +{ + bool hex =3D false; + int idx, bytes; + u32 fmsk, val; + + out->prf(out->dst, " %s: W%d: ", + vcap_actionfield_name(vctrl, action), + actionfield[action].width); + + switch (actionfield[action].type) { + case VCAP_FIELD_BIT: + out->prf(out->dst, "%d", value[0]); + break; + case VCAP_FIELD_U32: + fmsk =3D (1 << actionfield[action].width) - 1; + val =3D *(u32 *)value; + out->prf(out->dst, "%u", val & fmsk); + break; + case VCAP_FIELD_U48: + case VCAP_FIELD_U56: + case VCAP_FIELD_U64: + case VCAP_FIELD_U72: + case VCAP_FIELD_U112: + case VCAP_FIELD_U128: + hex =3D true; + break; + } + if (hex) { + bytes =3D DIV_ROUND_UP(actionfield[action].width, BITS_PER_BYTE); + out->prf(out->dst, "0x"); + for (idx =3D 0; idx < bytes; ++idx) + out->prf(out->dst, "%02x", value[bytes - idx - 1]); + } + out->prf(out->dst, "\n"); +} + +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; + const struct vcap_field *keyfield; + enum vcap_type vt =3D admin->vtype; + const struct vcap_typegroup *tgt; + 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; + res =3D vcap_find_keystream_keyset(vctrl, vt, keystream, maskstream, + false, 0); + if (res < 0) { + pr_err("%s:%d: could not find valid keyset: %d\n", + __func__, __LINE__, res); + return -EINVAL; + } + keyset =3D res; + out->prf(out->dst, " keyset: %s\n", + vcap_keyset_name(vctrl, ri->data.keyset)); + 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); + } + return 0; +} + +static int vcap_debugfs_show_rule_actionset(struct vcap_rule_internal *ri, + struct vcap_output_print *out) +{ + 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; + 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); + } + return 0; +} + static void vcap_show_admin_rule(struct vcap_control *vctrl, struct vcap_admin *admin, struct vcap_output_print *out, @@ -276,10 +581,8 @@ static void vcap_show_admin_rule(struct vcap_control *= vctrl, out->prf(out->dst, " chain_id: %d\n", ri->data.vcap_chain_id); out->prf(out->dst, " user: %d\n", ri->data.user); out->prf(out->dst, " priority: %d\n", ri->data.priority); - out->prf(out->dst, " keyset: %s\n", - vcap_keyset_name(vctrl, ri->data.keyset)); - out->prf(out->dst, " actionset: %s\n", - vcap_actionset_name(vctrl, ri->data.actionset)); + vcap_debugfs_show_rule_keyset(ri, out); + vcap_debugfs_show_rule_actionset(ri, out); } =20 static void vcap_show_admin_info(struct vcap_control *vctrl, diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h b/drive= rs/net/ethernet/microchip/vcap/vcap_api_private.h index b13e1c000c30..c447da2da683 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h @@ -77,6 +77,22 @@ const struct vcap_field *vcap_keyfields(struct vcap_cont= rol *vctrl, =20 /* Actionset and actionfield functionality */ =20 +/* Return the actionset information for the actionset */ +const struct vcap_set * +vcap_actionfieldset(struct vcap_control *vctrl, + enum vcap_type vt, enum vcap_actionfield_set actionset); +/* Return the number of actionfields in the actionset */ +int vcap_actionfield_count(struct vcap_control *vctrl, + enum vcap_type vt, + enum vcap_actionfield_set actionset); +/* Return the typegroup table for the matching actionset (using subword si= ze) */ +const struct vcap_typegroup * +vcap_actionfield_typegroup(struct vcap_control *vctrl, + enum vcap_type vt, enum vcap_actionfield_set actionset); +/* Return the list of actionfields for the actionset */ +const struct vcap_field * +vcap_actionfields(struct vcap_control *vctrl, + enum vcap_type vt, enum vcap_actionfield_set actionset); /* Map actionset id to a string with the actionset name */ const char *vcap_actionset_name(struct vcap_control *vctrl, enum vcap_actionfield_set actionset); diff --git a/support b/support new file mode 160000 index 000000000000..fcb2abd961e8 --- /dev/null +++ b/support @@ -0,0 +1 @@ +Subproject commit fcb2abd961e884577b51e677216a3cf84a870fca --=20 2.38.1