| Message ID | 20250707090720.750031-1-a-limaye@ti.com |
|---|---|
| State | Accepted |
| Delegated to: | Ryan Eatmon |
| Headers | show |
| Series | [meta-arago,scarthgap] meta-arago-distro: ethtool: Add patch to dump CPSW registers for K3 SoCs | expand |
I wonder if the patch itself is malformed - specifically if it has windows newlines that result in interlaced empty lines in mutt on Linux, as seen below. While .inc and .bbappend seem fine. On Mon, Jul 07, 2025 at 02:37:20PM +0530, Aniket Limaye via lists.yoctoproject.org wrote: > Add support for TI K3 CPSW register and ALE table dump through the > ethtool userspace utility. > > Signed-off-by: Aniket Limaye <a-limaye@ti.com> > --- > .../ethtool/ethtool-arago.inc | 8 + > ...k3-cpsw-registers-and-ale-table-dump.patch | 574 ++++++++++++++++++ > .../ethtool/ethtool_%.bbappend | 4 + > 3 files changed, 586 insertions(+) > create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc > create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch > create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend > > diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc > new file mode 100644 > index 00000000..5fd05a85 > --- /dev/null > +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc > @@ -0,0 +1,8 @@ > +PR:append = ".arago0" > + > +FILESEXTRAPATHS:prepend := "${THISDIR}/ethtool:" > + > +SRC_URI:append = " \ > + file://pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch \ > + " > + > diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch > new file mode 100644 > index 00000000..a14089b4 > --- /dev/null > +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch > @@ -0,0 +1,574 @@ > +From: Chintan Vankar <c-vankar@ti.com> > > +Subject: [PATCH] pretty: Add support for TI K3 CPSW registers and ALE table dump > > +Date: Thu, 3 Jul 2025 12:02:46 +0530 > > + > > +Add support to dump CPSW registers and ALE table for the CPSW instances on > > +K3 SoCs that are configured using the am65-cpsw-nuss.c device-driver in > > +Linux. > > + > > +Upstream-Status: Submitted [https://lore.kernel.org/all/20250705134807.3514891-1-c-vankar@ti.com/] > > +Signed-off-by: Chintan Vankar <c-vankar@ti.com> > > +--- > > + Makefile.am | 2 +- > > + am65-cpsw-nuss.c | 510 +++++++++++++++++++++++++++++++++++++++++++++++ > > + ethtool.c | 1 + > > + internal.h | 3 + > > + 4 files changed, 515 insertions(+), 1 deletion(-) > > + create mode 100644 am65-cpsw-nuss.c > > + > > +diff --git a/Makefile.am b/Makefile.am > > +index b9e06ad..fe6afcb 100644 > > +--- a/Makefile.am > > ++++ b/Makefile.am > > +@@ -23,7 +23,7 @@ ethtool_SOURCES += \ > > + smsc911x.c at76c50x-usb.c sfc.c stmmac.c \ > > + sff-common.c sff-common.h sfpid.c sfpdiag.c \ > > + ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c \ > > +- igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c > > ++ igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c am65-cpsw-nuss.c > > + endif > > + > > + if ENABLE_BASH_COMPLETION > > +diff --git a/am65-cpsw-nuss.c b/am65-cpsw-nuss.c > > +new file mode 100644 > > +index 0000000..de8e3e9 > > +--- /dev/null > > ++++ b/am65-cpsw-nuss.c > > +@@ -0,0 +1,510 @@ > > ++// SPDX-License-Identifier: GPL-2.0-only OR MIT > > ++/* Code to dump registers and ALE table for the CPSW instances on K3 SoCs that are configured using > > ++ * the am65-cpsw-nuss device-driver in Linux. > > ++ * > > ++ * Copyright (C) 2025 Texas Instruments > > ++ * Author: Chintan Vankar <c-vankar@ti.com> > > ++ */ > > ++ > > ++#include <stdio.h> > > ++#include <string.h> > > ++ > > ++#include "internal.h" > > ++ > > ++#define ALE_ENTRY_BITS 74 > > ++#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) > > ++ > > ++#define ALE_ENTRY_FREE 0x0 > > ++#define ALE_ENTRY_ADDR 0x1 > > ++#define ALE_ENTRY_VLAN 0x2 > > ++#define ALE_ENTRY_VLAN_ADDR 0x3 > > ++ > > ++#define BIT(nr) (1 << (nr)) > > ++#define BITMASK(bits) (BIT(bits) - 1) > > ++ > > ++/* ALE word specifiers */ > > ++#define NUM_ALE_WORDS 2 > > ++#define ALE_WORD_LEN 32 > > ++ > > ++/* MAC address specifiers */ > > ++#define MAC_START_BIT 40 > > ++#define MAC_OCTET_LEN 8 > > ++#define NUM_MAC_OCTET 6 > > ++ > > ++/* RTL version specifiers */ > > ++#define RTL_VERSION_MASK 0xF800 > > ++#define CPSW2G_RTL_VERSION 0x3800 > > ++#define CPSW3G_RTL_VERSION 0x0 > > ++ > > ++/* OUI address uses format xx:xx:xx, use OUI shift as 16 bits and MASK as 0xFF to parse the same*/ > > ++#define OUI_ADDR_SHIFT 16 > > ++#define OUI_ADDR_MASK 0xFF > > ++ > > ++/* VLAN entry specifiers */ > > ++#define VLAN_INNER_ENTRY 0x0 > > ++#define VLAN_OUTER_ENTRY 0x2 > > ++#define VLAN_ETHERTYPE_ENTRY 0x4 > > ++#define VLAN_IPV4_ENTRY 0x6 > > ++#define VLAN_IPV6_ENTRY_MASK 0x1 > > ++ > > ++/* VLAN Inner/Outer table entry MASKs and SHIFTs*/ > > ++#define NOLEARN_FLAG_SHIFT 2 > > ++#define NOLEARN_FLAG_MASK 0x1FF > > ++#define INGRESS_CHECK_SHIFT 1 > > ++#define INGRESS_CHECK_MASK 0x1 > > ++#define VLAN_ID_SHIFT 16 > > ++#define VLAN_ID_MASK 0xFFF > > ++#define NOFRAG_FLAG_SHIFT_2G 12 > > ++#define NOFRAG_FLAG_MASK_2G 0x1 > > ++#define NOFRAG_FLAG_SHIFT 15 > > ++#define NOFRAG_FLAG_MASK 0x1 > > ++#define REG_MASK_SHIFT 4 > > ++#define REG_MASK_MASK 0x1FF > > ++#define PKT_EGRESS_W1_MASK 0x1 > > ++#define PKT_EGRESS_W1_OFFSET 512 > > ++#define PKT_EGRESS_SHIFT 24 > > ++#define PKT_EGRESS_MASK_2G 0x3 > > ++#define PKT_EGRESS_MASK 0x1FF > > ++#define UNREG_MASK_SHIFT_2G 20 > > ++#define UNREG_MASK_MASK_2G 0x7 > > ++#define UNREG_MASK_SHIFT 12 > > ++#define UNREG_MASK_MASK 0x1FF > > ++#define NXT_HDR_CTRL_SHIFT_2G 19 > > ++#define NXT_HDR_CTRL_MASK_2G 0x1 > > ++#define NXT_HDR_CTRL_SHIFT 23 > > ++#define NXT_HDR_CTRL_MASK 0x1 > > ++#define VLAN_MEMBER_LIST_MASK_2G 0x3 > > ++#define VLAN_MEMBER_LIST_MASK 0x1FF > > ++ > > ++/* VLAN IPv4 entry MASKs and SHIFTs*/ > > ++#define IPV4_ADDR_OCT1_SHIFT 24 > > ++#define IPV4_ADDR_OCT2_SHIFT 16 > > ++#define IPV4_ADDR_OCT3_SHIFT 8 > > ++#define IPV4_ADDR_MASK 0xFF > > ++ > > ++/* VLAN IPv6 entry MASKs and SHIFTs*/ > > ++#define IPV6_HIGH_ENTRY_FLAG 0x40 > > ++#define IPV6_IGNMCBITS_MASK 0xFF > > ++#define IPV6_HADDR_W1_SHIFT 12 > > ++#define IPV6_HADDR_W1_MASK_1 0xFFFF > > ++#define IPV6_HADDR_W1_MASK_2 0xFFF > > ++#define IPV6_HADDR_W0_SHIFT_1 28 > > ++#define IPV6_HADDR_W0_MASK_1 0xF > > ++#define IPV6_HADDR_W0_SHIFT_2 12 > > ++#define IPV6_HADDR_W0_MASK_2 0xFFFF > > ++#define IPV6_LADDR_W2_SHIFT 4 > > ++#define IPV6_LADDR_W2_MAKS 0xF > > ++#define IPV6_LADDR_W1_SHIFT 16 > > ++#define IPV6_LADDR_W1_MASK_1 0xFFF > > ++#define IPV6_LADDR_W1_MASK 0xFFFF > > ++#define IPV6_LADDR_W0_SHIFT 16 > > ++#define IPV6_LADDR_W0_MASK 0xFFFF > > ++ > > ++/** > > ++ * Since there are different instances of CPSW (namely cpsw2g, cpsw3g, cpsw5g and cpsw9g) > > ++ * some register offsets differ to get some parameters for ALE table, parse rtl_version > > ++ * from ALE_MOD_VER register to determine which instance is being used. > > ++ */ > > ++u32 rtl_version; > > ++ > > ++static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) > > ++{ > > ++ int idx; > > ++ > > ++ idx = start / ALE_WORD_LEN; > > ++ start -= idx * ALE_WORD_LEN; > > ++ > > ++ /** > > ++ * ALE words are stored in order word2, word1 and word0, flip the word to parse in numeric > > ++ * order > > ++ */ > > ++ idx = NUM_ALE_WORDS - idx; /* flip */ > > ++ return (ale_entry[idx] >> start) & BITMASK(bits); > > ++} > > ++ > > ++#define DEFINE_ALE_FIELD(name, start, bits) \ > > ++static inline int cpsw_ale_get_##name(u32 *ale_entry) \ > > ++{ \ > > ++ return cpsw_ale_get_field(ale_entry, start, bits); \ > > ++} > > ++ > > ++DEFINE_ALE_FIELD(entry_type, 60, 2) > > ++DEFINE_ALE_FIELD(vlan_id, 48, 12) > > ++DEFINE_ALE_FIELD(mcast_state, 62, 2) > > ++DEFINE_ALE_FIELD(port_mask, 66, 9) > > ++DEFINE_ALE_FIELD(super, 65, 1) > > ++DEFINE_ALE_FIELD(agable, 62, 1) > > ++DEFINE_ALE_FIELD(touched, 63, 1) > > ++DEFINE_ALE_FIELD(ucast_type, 62, 2) > > ++DEFINE_ALE_FIELD(port_num, 66, 4) > > ++DEFINE_ALE_FIELD(port_num_2g, 66, 1) > > ++DEFINE_ALE_FIELD(port_num_3g, 66, 2) > > ++DEFINE_ALE_FIELD(blocked, 65, 1) > > ++DEFINE_ALE_FIELD(secure, 64, 1) > > ++DEFINE_ALE_FIELD(oui_entry, 62, 2) > > ++DEFINE_ALE_FIELD(oui_addr, 4, 24) > > ++DEFINE_ALE_FIELD(mcast, 40, 1) > > ++DEFINE_ALE_FIELD(vlan_entry_type, 62, 3) > > ++DEFINE_ALE_FIELD(ethertype, 0, 16) > > ++DEFINE_ALE_FIELD(ipv4_addr, 0, 32) > > ++DEFINE_ALE_FIELD(ingress_bits, 65, 5) > > ++DEFINE_ALE_FIELD(ipv6_addr_low, 0, 60) > > ++DEFINE_ALE_FIELD(ipv6_addr_mid, 63, 8) > > ++DEFINE_ALE_FIELD(ipv6_addr_high, 0, 60) > > ++DEFINE_ALE_FIELD(entry_word0, 0, 32) > > ++DEFINE_ALE_FIELD(entry_word1, 32, 32) > > ++DEFINE_ALE_FIELD(entry_word2, 64, 12) > > ++ > > ++static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) > > ++{ > > ++ int i; > > ++ > > ++ for (i = 0; i < NUM_MAC_OCTET; i++) > > ++ addr[i] = cpsw_ale_get_field(ale_entry, MAC_START_BIT - MAC_OCTET_LEN * i, > > ++ MAC_OCTET_LEN); > > ++} > > ++ > > ++struct k3_cpsw_regdump_hdr { > > ++ u32 module_id; > > ++ u32 len; > > ++}; > > ++ > > ++enum { > > ++ K3_CPSW_REGDUMP_MOD_NUSS = 1, > > ++ K3_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, > > ++ K3_CPSW_REGDUMP_MOD_MDIO = 3, > > ++ K3_CPSW_REGDUMP_MOD_CPSW = 4, > > ++ K3_CPSW_REGDUMP_MOD_CPSW_P0 = 5, > > ++ K3_CPSW_REGDUMP_MOD_CPSW_PN = 6, > > ++ K3_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, > > ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE = 8, > > ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, > > ++ K3_CPSW_REGDUMP_MOD_LAST, > > ++}; > > ++ > > ++static const char *mod_names[K3_CPSW_REGDUMP_MOD_LAST] = { > > ++ [K3_CPSW_REGDUMP_MOD_NUSS] = "cpsw-nuss", > > ++ [K3_CPSW_REGDUMP_MOD_RGMII_STATUS] = "cpsw-nuss-rgmii-status", > > ++ [K3_CPSW_REGDUMP_MOD_MDIO] = "cpsw-nuss-mdio", > > ++ [K3_CPSW_REGDUMP_MOD_CPSW] = "cpsw-nu", > > ++ [K3_CPSW_REGDUMP_MOD_CPSW_P0] = "cpsw-nu-p0", > > ++ [K3_CPSW_REGDUMP_MOD_CPSW_PN] = "cpsw-nu-pn", > > ++ [K3_CPSW_REGDUMP_MOD_CPSW_CPTS] = "cpsw-nu-cpts", > > ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE] = "cpsw-nu-ale", > > ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL] = "cpsw-nu-ale-tbl", > > ++}; > > ++ > > ++static void cpsw_ale_dump_oui_entry(int index, u32 *ale_entry) > > ++{ > > ++ u32 oui_addr; > > ++ > > ++ oui_addr = cpsw_ale_get_oui_addr(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: OUI Unicast\n, \tOUI = %02x:%02x:%02x\n", > > ++ index, (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, > > ++ (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, oui_addr & OUI_ADDR_MASK); > > ++} > > ++ > > ++static void cpsw_ale_dump_addr(int index, u32 *ale_entry) > > ++{ > > ++ u8 addr[NUM_MAC_OCTET]; > > ++ > > ++ cpsw_ale_get_addr(ale_entry, addr); > > ++ > > ++ if (cpsw_ale_get_mcast(ale_entry)) { > > ++ static const char * const str_mcast_state[] = {"Forwarding", > > ++ "Blocking/Forwarding/Learning", > > ++ "Learning/Forwarding", > > ++ "Forwarding"}; > > ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); > > ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); > > ++ u8 super = cpsw_ale_get_super(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: Multicast\n \tAddress = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_State = %s, %sSuper, port_mask = 0x%x\n", > > ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], > > ++ str_mcast_state[state], super ? "" : "No ", port_mask); > > ++ } else { > > ++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", > > ++ "Touched"}; > > ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); > > ++ u8 port_num = cpsw_ale_get_port_num(ale_entry); > > ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); > > ++ u8 touched = cpsw_ale_get_touched(ale_entry); > > ++ u8 secure = cpsw_ale_get_secure(ale_entry); > > ++ u8 agable = cpsw_ale_get_agable(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: Unicast\n \tUpdated Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast Type = %s, Port_num = 0x%x, Secure: %d, Blocked: %d, Touch = %d, Agable = %d\n", > > ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], > > ++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); > > ++ } > > ++} > > ++ > > ++static void cpsw_ale_dump_inner_vlan_entry(int index, u32 *ale_entry) > > ++{ > > ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); > > ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); > > ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: Inner VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", > > ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, > > ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); > > ++ > > ++ if (rtl_version == CPSW2G_RTL_VERSION) { > > ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", > > ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, > > ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, > > ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); > > ++ > > ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", > > ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, > > ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, > > ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, > > ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); > > ++ } else { > > ++ fprintf(stdout, "\tVLAN ID = %d, Registered Mask = 0x%x, No Frag = %d\n", > > ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, > > ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK, > > ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK); > > ++ > > ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x, Members = 0x%x\n", > > ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + > > ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), > > ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, > > ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, > > ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); > > ++ } > > ++} > > ++ > > ++static void cpsw_ale_dump_outer_vlan_entry(int index, u32 *ale_entry) > > ++{ > > ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); > > ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); > > ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: Outer VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", > > ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, > > ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); > > ++ > > ++ if (rtl_version == CPSW2G_RTL_VERSION) { > > ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", > > ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, > > ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, > > ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); > > ++ > > ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", > > ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, > > ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, > > ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, > > ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); > > ++ } else { > > ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", > > ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, > > ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK, > > ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); > > ++ > > ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x Members = 0x%x\n", > > ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + > > ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), > > ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, > > ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, > > ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); > > ++ } > > ++} > > ++ > > ++static void cpsw_ale_dump_ethertype_entry(int index, u32 *ale_entry) > > ++{ > > ++ u16 ethertype = cpsw_ale_get_ethertype(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: VLAN Ethertype\n \tEthertype = 0x%x\n", index, ethertype); > > ++} > > ++ > > ++static void cpsw_ale_dump_ipv4_entry(int index, u32 *ale_entry) > > ++{ > > ++ u8 ingress_bits = cpsw_ale_get_ingress_bits(ale_entry); > > ++ u32 ipv4_addr = cpsw_ale_get_ipv4_addr(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: VLAN IPv4\n \tIngress Bits: 0x%x IPv4 Address = %u.%u.%u.%u\n", > > ++ index, ingress_bits, ipv4_addr >> IPV4_ADDR_OCT1_SHIFT & IPV4_ADDR_MASK, > > ++ ipv4_addr >> IPV4_ADDR_OCT2_SHIFT & IPV4_ADDR_MASK, > > ++ ipv4_addr >> IPV4_ADDR_OCT3_SHIFT & IPV4_ADDR_MASK, ipv4_addr & IPV4_ADDR_MASK); > > ++} > > ++ > > ++static void cpsw_ale_dump_ipv6_entry(int index, u32 *ale_entry) > > ++{ > > ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); > > ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); > > ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); > > ++ > > ++ if (index & IPV6_HIGH_ENTRY_FLAG) { > > ++ fprintf(stdout, "%d: Type: VLAN IPv6 Higher Entry (Lower Bit entry at %04u)\n \tIgnored Multicast bits: 0x%x, IPv6 Address (Bits [127:68]) = %04x:%03x%01x:%04x:%03x\n", > > ++ index, (index & (~IPV6_HIGH_ENTRY_FLAG)), > > ++ vlan_entry_word2 & IPV6_IGNMCBITS_MASK, > > ++ (vlan_entry_word1 >> IPV6_HADDR_W1_SHIFT) & IPV6_HADDR_W1_MASK_1, > > ++ vlan_entry_word1 & IPV6_HADDR_W1_MASK_2, > > ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_1) & IPV6_HADDR_W0_MASK_1, > > ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_2) & IPV6_HADDR_W0_MASK_2, > > ++ vlan_entry_word0 & IPV6_HADDR_W0_MASK_2); > > ++ } else { > > ++ fprintf(stdout, "%d: Type: VLAN IPv6 Lower Entry (Higher Bit entry at %04u)\n \tIPv6 Address (Bits [127:68]) = %01x:%01x%03x:%04x:%04x:%04x\n", > > ++ index, (index | IPV6_HIGH_ENTRY_FLAG), > > ++ (vlan_entry_word2 >> IPV6_LADDR_W2_SHIFT) & IPV6_LADDR_W2_MAKS, > > ++ vlan_entry_word2 & IPV6_LADDR_W2_MAKS, > > ++ (vlan_entry_word1 >> IPV6_LADDR_W1_SHIFT) & IPV6_LADDR_W1_MASK_1, > > ++ vlan_entry_word1 & IPV6_LADDR_W1_MASK, > > ++ (vlan_entry_word0 >> IPV6_LADDR_W0_SHIFT) & IPV6_LADDR_W0_MASK, > > ++ vlan_entry_word0 & IPV6_LADDR_W0_MASK); > > ++ } > > ++} > > ++ > > ++static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry) > > ++{ > > ++ u8 addr[NUM_MAC_OCTET]; > > ++ int vlan = cpsw_ale_get_vlan_id(ale_entry); > > ++ > > ++ cpsw_ale_get_addr(ale_entry, addr); > > ++ if (cpsw_ale_get_mcast(ale_entry)) { > > ++ static const char * const str_mcast_state[] = {"Forwarding", > > ++ "Blocking/Forwarding/Learning", > > ++ "Learning/Forwarding", > > ++ "Forwarding"}; > > ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); > > ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); > > ++ u8 super = cpsw_ale_get_super(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: Multicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_state = %s, %s Super, port_mask = 0x%x\n", > > ++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], > > ++ str_mcast_state[state], super ? "" : "No ", port_mask); > > ++ } else { > > ++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", > > ++ "Touched"}; > > ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); > > ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); > > ++ u8 touched = cpsw_ale_get_touched(ale_entry); > > ++ u8 secure = cpsw_ale_get_secure(ale_entry); > > ++ u8 agable = cpsw_ale_get_agable(ale_entry); > > ++ > > ++ int port_num; > > ++ > > ++ if (rtl_version == CPSW2G_RTL_VERSION) > > ++ port_num = cpsw_ale_get_port_num_2g(ale_entry); > > ++ else if (rtl_version == CPSW3G_RTL_VERSION) > > ++ port_num = cpsw_ale_get_port_num_3g(ale_entry); > > ++ else > > ++ port_num = cpsw_ale_get_port_num(ale_entry); > > ++ > > ++ fprintf(stdout, "%d: Type: Unicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast_type = %s, port_num = 0x%x, Secure = %d, Blocked = %d, Touch = %d, Agable = %d\n", > > ++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], > > ++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); > > ++ } > > ++} > > ++ > > ++void cpsw_dump_ale(struct k3_cpsw_regdump_hdr *ale_hdr, u32 *ale_pos) > > ++{ > > ++ int i, ale_entries; > > ++ > > ++ if (!ale_hdr) > > ++ return; > > ++ > > ++ ale_entries = (ale_hdr->len - sizeof(struct k3_cpsw_regdump_hdr)) / > > ++ ALE_ENTRY_WORDS / sizeof(u32); > > ++ > > ++ printf("Number of ALE entries: %d\n", ale_entries); > > ++ ale_pos += 2; > > ++ for (i = 0; i < ale_entries; i++) { > > ++ int type; > > ++ > > ++ type = cpsw_ale_get_entry_type(ale_pos); > > ++ > > ++ switch (type) { > > ++ case ALE_ENTRY_FREE: > > ++ break; > > ++ > > ++ case ALE_ENTRY_ADDR: > > ++ u32 oui_entry = cpsw_ale_get_oui_addr(ale_pos); > > ++ > > ++ if (oui_entry == 0x2) > > ++ cpsw_ale_dump_oui_entry(i, ale_pos); > > ++ else > > ++ cpsw_ale_dump_addr(i, ale_pos); > > ++ break; > > ++ > > ++ case ALE_ENTRY_VLAN: > > ++ u32 vlan_entry_type = cpsw_ale_get_vlan_entry_type(ale_pos); > > ++ > > ++ if (vlan_entry_type == VLAN_INNER_ENTRY) > > ++ cpsw_ale_dump_inner_vlan_entry(i, ale_pos); > > ++ else if (vlan_entry_type == VLAN_OUTER_ENTRY) > > ++ cpsw_ale_dump_outer_vlan_entry(i, ale_pos); > > ++ else if (vlan_entry_type == VLAN_ETHERTYPE_ENTRY) > > ++ cpsw_ale_dump_ethertype_entry(i, ale_pos); > > ++ else if (vlan_entry_type == VLAN_IPV4_ENTRY) > > ++ cpsw_ale_dump_ipv4_entry(i, ale_pos); > > ++ else if (vlan_entry_type & VLAN_IPV6_ENTRY_MASK) > > ++ cpsw_ale_dump_ipv6_entry(i, ale_pos); > > ++ break; > > ++ > > ++ case ALE_ENTRY_VLAN_ADDR: > > ++ cpsw_ale_dump_vlan_addr(i, ale_pos); > > ++ break; > > ++ > > ++ default: > > ++ break; > > ++ } > > ++ > > ++ ale_pos += ALE_ENTRY_WORDS; > > ++ } > > ++} > > ++ > > ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused, > > ++ struct ethtool_regs *regs) > > ++{ > > ++ struct k3_cpsw_regdump_hdr *dump_hdr, *ale_hdr = NULL; > > ++ u32 *reg = (u32 *)regs->data, *ale_pos; > > ++ u32 mod_id; > > ++ int i, regdump_len = info->regdump_len; > > ++ > > ++ fprintf(stdout, "K3 CPSW dump version: %d, len: %d\n", > > ++ regs->version, info->regdump_len); > > ++ fprintf(stdout, "(Missing registers in memory space can be considered as zero valued)\n"); > > ++ > > ++ /* Line break before register dump */ > > ++ fprintf(stdout, "--------------------------------------------------------------------\n"); > > ++ i = 0; > > ++ do { > > ++ u32 *tmp, j; > > ++ u32 num_items; > > ++ > > ++ dump_hdr = (struct k3_cpsw_regdump_hdr *)reg; > > ++ mod_id = dump_hdr->module_id; > > ++ > > ++ num_items = dump_hdr->len / sizeof(u32); > > ++ > > ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE) > > ++ rtl_version = reg[3] & RTL_VERSION_MASK; > > ++ > > ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { > > ++ ale_hdr = dump_hdr; > > ++ ale_pos = reg; > > ++ break; > > ++ } > > ++ > > ++ fprintf(stdout, "%s regdump: number of Registers:(%d)\n", > > ++ mod_names[mod_id], num_items - 2); > > ++ tmp = reg; > > ++ /* Values are stored in pair as reg_offset-reg_val, hence parse the same way*/ > > ++ for (j = 2; j < num_items; j += 2) { > > ++ if (tmp[j + 1] != 0x0) > > ++ fprintf(stdout, "%08x:reg(%08X)\n", tmp[j], tmp[j + 1]); > > ++ } > > ++ > > ++ reg += num_items; > > ++ i += dump_hdr->len; > > ++ } while (i < regdump_len); > > ++ > > ++ /* Adding a boundary in between Register dump and ALE table */ > > ++ fprintf(stdout, "--------------------------\n"); > > ++ > > ++ cpsw_dump_ale(ale_hdr, ale_pos); > > ++ > > ++ return 0; > > ++}; > > +diff --git a/ethtool.c b/ethtool.c > > +index 3ac15a7..a383eb6 100644 > > +--- a/ethtool.c > > ++++ b/ethtool.c > > +@@ -1162,6 +1162,7 @@ static const struct { > > + { "fsl_enetc", fsl_enetc_dump_regs }, > > + { "fsl_enetc_vf", fsl_enetc_dump_regs }, > > + { "hns3", hns3_dump_regs }, > > ++ { "am65-cpsw-nuss", am65_cpsw_dump_regs }, > > + }; > > + #endif > > + > > +diff --git a/internal.h b/internal.h > > +index 4b994f5..81212b4 100644 > > +--- a/internal.h > > ++++ b/internal.h > > +@@ -410,4 +410,7 @@ int cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); > > + /* Microchip Ethernet Controller */ > > + int lan743x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); > > + > > ++/* TI K3 CPSW Ethernet Switch */ > > ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); > > ++ > > + #endif /* ETHTOOL_INTERNAL_H__ */ > > +-- > > +2.34.1 > > + > > diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend > new file mode 100644 > index 00000000..3b388151 > --- /dev/null > +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend > @@ -0,0 +1,4 @@ > +ETHTOOL_ARAGO = "" > +ETHTOOL_ARAGO:arago = "ethtool-arago.inc" > + > +require ${ETHTOOL_ARAGO} > -- > 2.34.1
On 11/07/25 06:02, Denys Dmytriyenko wrote: > I wonder if the patch itself is malformed - specifically if it has windows > newlines that result in interlaced empty lines in mutt on Linux, as seen > below. While .inc and .bbappend seem fine. > Chintan, Yeah looks like the patchfile I added was not properly formatted. I will try resending this one quickly. Thanks, Aniket > > On Mon, Jul 07, 2025 at 02:37:20PM +0530, Aniket Limaye via lists.yoctoproject.org wrote: >> Add support for TI K3 CPSW register and ALE table dump through the >> ethtool userspace utility. >> >> Signed-off-by: Aniket Limaye <a-limaye@ti.com> >> --- >> .../ethtool/ethtool-arago.inc | 8 + >> ...k3-cpsw-registers-and-ale-table-dump.patch | 574 ++++++++++++++++++ >> .../ethtool/ethtool_%.bbappend | 4 + >> 3 files changed, 586 insertions(+) >> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >> >> diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >> new file mode 100644 >> index 00000000..5fd05a85 >> --- /dev/null >> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >> @@ -0,0 +1,8 @@ >> +PR:append = ".arago0" >> + >> +FILESEXTRAPATHS:prepend := "${THISDIR}/ethtool:" >> + >> +SRC_URI:append = " \ >> + file://pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch \ >> + " >> + >> diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >> new file mode 100644 >> index 00000000..a14089b4 >> --- /dev/null >> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >> @@ -0,0 +1,574 @@ >> +From: Chintan Vankar <c-vankar@ti.com> >> >> +Subject: [PATCH] pretty: Add support for TI K3 CPSW registers and ALE table dump >> >> +Date: Thu, 3 Jul 2025 12:02:46 +0530 >> >> + >> >> +Add support to dump CPSW registers and ALE table for the CPSW instances on >> >> +K3 SoCs that are configured using the am65-cpsw-nuss.c device-driver in >> >> +Linux. >> >> + >> >> +Upstream-Status: Submitted [https://lore.kernel.org/all/20250705134807.3514891-1-c-vankar@ti.com/] >> >> +Signed-off-by: Chintan Vankar <c-vankar@ti.com> >> >> +--- >> >> + Makefile.am | 2 +- >> >> + am65-cpsw-nuss.c | 510 +++++++++++++++++++++++++++++++++++++++++++++++ >> >> + ethtool.c | 1 + >> >> + internal.h | 3 + >> >> + 4 files changed, 515 insertions(+), 1 deletion(-) >> >> + create mode 100644 am65-cpsw-nuss.c >> >> + >> >> +diff --git a/Makefile.am b/Makefile.am >> >> +index b9e06ad..fe6afcb 100644 >> >> +--- a/Makefile.am >> >> ++++ b/Makefile.am >> >> +@@ -23,7 +23,7 @@ ethtool_SOURCES += \ >> >> + smsc911x.c at76c50x-usb.c sfc.c stmmac.c \ >> >> + sff-common.c sff-common.h sfpid.c sfpdiag.c \ >> >> + ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c \ >> >> +- igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c >> >> ++ igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c am65-cpsw-nuss.c >> >> + endif >> >> + >> >> + if ENABLE_BASH_COMPLETION >> >> +diff --git a/am65-cpsw-nuss.c b/am65-cpsw-nuss.c >> >> +new file mode 100644 >> >> +index 0000000..de8e3e9 >> >> +--- /dev/null >> >> ++++ b/am65-cpsw-nuss.c >> >> +@@ -0,0 +1,510 @@ >> >> ++// SPDX-License-Identifier: GPL-2.0-only OR MIT >> >> ++/* Code to dump registers and ALE table for the CPSW instances on K3 SoCs that are configured using >> >> ++ * the am65-cpsw-nuss device-driver in Linux. >> >> ++ * >> >> ++ * Copyright (C) 2025 Texas Instruments >> >> ++ * Author: Chintan Vankar <c-vankar@ti.com> >> >> ++ */ >> >> ++ >> >> ++#include <stdio.h> >> >> ++#include <string.h> >> >> ++ >> >> ++#include "internal.h" >> >> ++ >> >> ++#define ALE_ENTRY_BITS 74 >> >> ++#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) >> >> ++ >> >> ++#define ALE_ENTRY_FREE 0x0 >> >> ++#define ALE_ENTRY_ADDR 0x1 >> >> ++#define ALE_ENTRY_VLAN 0x2 >> >> ++#define ALE_ENTRY_VLAN_ADDR 0x3 >> >> ++ >> >> ++#define BIT(nr) (1 << (nr)) >> >> ++#define BITMASK(bits) (BIT(bits) - 1) >> >> ++ >> >> ++/* ALE word specifiers */ >> >> ++#define NUM_ALE_WORDS 2 >> >> ++#define ALE_WORD_LEN 32 >> >> ++ >> >> ++/* MAC address specifiers */ >> >> ++#define MAC_START_BIT 40 >> >> ++#define MAC_OCTET_LEN 8 >> >> ++#define NUM_MAC_OCTET 6 >> >> ++ >> >> ++/* RTL version specifiers */ >> >> ++#define RTL_VERSION_MASK 0xF800 >> >> ++#define CPSW2G_RTL_VERSION 0x3800 >> >> ++#define CPSW3G_RTL_VERSION 0x0 >> >> ++ >> >> ++/* OUI address uses format xx:xx:xx, use OUI shift as 16 bits and MASK as 0xFF to parse the same*/ >> >> ++#define OUI_ADDR_SHIFT 16 >> >> ++#define OUI_ADDR_MASK 0xFF >> >> ++ >> >> ++/* VLAN entry specifiers */ >> >> ++#define VLAN_INNER_ENTRY 0x0 >> >> ++#define VLAN_OUTER_ENTRY 0x2 >> >> ++#define VLAN_ETHERTYPE_ENTRY 0x4 >> >> ++#define VLAN_IPV4_ENTRY 0x6 >> >> ++#define VLAN_IPV6_ENTRY_MASK 0x1 >> >> ++ >> >> ++/* VLAN Inner/Outer table entry MASKs and SHIFTs*/ >> >> ++#define NOLEARN_FLAG_SHIFT 2 >> >> ++#define NOLEARN_FLAG_MASK 0x1FF >> >> ++#define INGRESS_CHECK_SHIFT 1 >> >> ++#define INGRESS_CHECK_MASK 0x1 >> >> ++#define VLAN_ID_SHIFT 16 >> >> ++#define VLAN_ID_MASK 0xFFF >> >> ++#define NOFRAG_FLAG_SHIFT_2G 12 >> >> ++#define NOFRAG_FLAG_MASK_2G 0x1 >> >> ++#define NOFRAG_FLAG_SHIFT 15 >> >> ++#define NOFRAG_FLAG_MASK 0x1 >> >> ++#define REG_MASK_SHIFT 4 >> >> ++#define REG_MASK_MASK 0x1FF >> >> ++#define PKT_EGRESS_W1_MASK 0x1 >> >> ++#define PKT_EGRESS_W1_OFFSET 512 >> >> ++#define PKT_EGRESS_SHIFT 24 >> >> ++#define PKT_EGRESS_MASK_2G 0x3 >> >> ++#define PKT_EGRESS_MASK 0x1FF >> >> ++#define UNREG_MASK_SHIFT_2G 20 >> >> ++#define UNREG_MASK_MASK_2G 0x7 >> >> ++#define UNREG_MASK_SHIFT 12 >> >> ++#define UNREG_MASK_MASK 0x1FF >> >> ++#define NXT_HDR_CTRL_SHIFT_2G 19 >> >> ++#define NXT_HDR_CTRL_MASK_2G 0x1 >> >> ++#define NXT_HDR_CTRL_SHIFT 23 >> >> ++#define NXT_HDR_CTRL_MASK 0x1 >> >> ++#define VLAN_MEMBER_LIST_MASK_2G 0x3 >> >> ++#define VLAN_MEMBER_LIST_MASK 0x1FF >> >> ++ >> >> ++/* VLAN IPv4 entry MASKs and SHIFTs*/ >> >> ++#define IPV4_ADDR_OCT1_SHIFT 24 >> >> ++#define IPV4_ADDR_OCT2_SHIFT 16 >> >> ++#define IPV4_ADDR_OCT3_SHIFT 8 >> >> ++#define IPV4_ADDR_MASK 0xFF >> >> ++ >> >> ++/* VLAN IPv6 entry MASKs and SHIFTs*/ >> >> ++#define IPV6_HIGH_ENTRY_FLAG 0x40 >> >> ++#define IPV6_IGNMCBITS_MASK 0xFF >> >> ++#define IPV6_HADDR_W1_SHIFT 12 >> >> ++#define IPV6_HADDR_W1_MASK_1 0xFFFF >> >> ++#define IPV6_HADDR_W1_MASK_2 0xFFF >> >> ++#define IPV6_HADDR_W0_SHIFT_1 28 >> >> ++#define IPV6_HADDR_W0_MASK_1 0xF >> >> ++#define IPV6_HADDR_W0_SHIFT_2 12 >> >> ++#define IPV6_HADDR_W0_MASK_2 0xFFFF >> >> ++#define IPV6_LADDR_W2_SHIFT 4 >> >> ++#define IPV6_LADDR_W2_MAKS 0xF >> >> ++#define IPV6_LADDR_W1_SHIFT 16 >> >> ++#define IPV6_LADDR_W1_MASK_1 0xFFF >> >> ++#define IPV6_LADDR_W1_MASK 0xFFFF >> >> ++#define IPV6_LADDR_W0_SHIFT 16 >> >> ++#define IPV6_LADDR_W0_MASK 0xFFFF >> >> ++ >> >> ++/** >> >> ++ * Since there are different instances of CPSW (namely cpsw2g, cpsw3g, cpsw5g and cpsw9g) >> >> ++ * some register offsets differ to get some parameters for ALE table, parse rtl_version >> >> ++ * from ALE_MOD_VER register to determine which instance is being used. >> >> ++ */ >> >> ++u32 rtl_version; >> >> ++ >> >> ++static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) >> >> ++{ >> >> ++ int idx; >> >> ++ >> >> ++ idx = start / ALE_WORD_LEN; >> >> ++ start -= idx * ALE_WORD_LEN; >> >> ++ >> >> ++ /** >> >> ++ * ALE words are stored in order word2, word1 and word0, flip the word to parse in numeric >> >> ++ * order >> >> ++ */ >> >> ++ idx = NUM_ALE_WORDS - idx; /* flip */ >> >> ++ return (ale_entry[idx] >> start) & BITMASK(bits); >> >> ++} >> >> ++ >> >> ++#define DEFINE_ALE_FIELD(name, start, bits) \ >> >> ++static inline int cpsw_ale_get_##name(u32 *ale_entry) \ >> >> ++{ \ >> >> ++ return cpsw_ale_get_field(ale_entry, start, bits); \ >> >> ++} >> >> ++ >> >> ++DEFINE_ALE_FIELD(entry_type, 60, 2) >> >> ++DEFINE_ALE_FIELD(vlan_id, 48, 12) >> >> ++DEFINE_ALE_FIELD(mcast_state, 62, 2) >> >> ++DEFINE_ALE_FIELD(port_mask, 66, 9) >> >> ++DEFINE_ALE_FIELD(super, 65, 1) >> >> ++DEFINE_ALE_FIELD(agable, 62, 1) >> >> ++DEFINE_ALE_FIELD(touched, 63, 1) >> >> ++DEFINE_ALE_FIELD(ucast_type, 62, 2) >> >> ++DEFINE_ALE_FIELD(port_num, 66, 4) >> >> ++DEFINE_ALE_FIELD(port_num_2g, 66, 1) >> >> ++DEFINE_ALE_FIELD(port_num_3g, 66, 2) >> >> ++DEFINE_ALE_FIELD(blocked, 65, 1) >> >> ++DEFINE_ALE_FIELD(secure, 64, 1) >> >> ++DEFINE_ALE_FIELD(oui_entry, 62, 2) >> >> ++DEFINE_ALE_FIELD(oui_addr, 4, 24) >> >> ++DEFINE_ALE_FIELD(mcast, 40, 1) >> >> ++DEFINE_ALE_FIELD(vlan_entry_type, 62, 3) >> >> ++DEFINE_ALE_FIELD(ethertype, 0, 16) >> >> ++DEFINE_ALE_FIELD(ipv4_addr, 0, 32) >> >> ++DEFINE_ALE_FIELD(ingress_bits, 65, 5) >> >> ++DEFINE_ALE_FIELD(ipv6_addr_low, 0, 60) >> >> ++DEFINE_ALE_FIELD(ipv6_addr_mid, 63, 8) >> >> ++DEFINE_ALE_FIELD(ipv6_addr_high, 0, 60) >> >> ++DEFINE_ALE_FIELD(entry_word0, 0, 32) >> >> ++DEFINE_ALE_FIELD(entry_word1, 32, 32) >> >> ++DEFINE_ALE_FIELD(entry_word2, 64, 12) >> >> ++ >> >> ++static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) >> >> ++{ >> >> ++ int i; >> >> ++ >> >> ++ for (i = 0; i < NUM_MAC_OCTET; i++) >> >> ++ addr[i] = cpsw_ale_get_field(ale_entry, MAC_START_BIT - MAC_OCTET_LEN * i, >> >> ++ MAC_OCTET_LEN); >> >> ++} >> >> ++ >> >> ++struct k3_cpsw_regdump_hdr { >> >> ++ u32 module_id; >> >> ++ u32 len; >> >> ++}; >> >> ++ >> >> ++enum { >> >> ++ K3_CPSW_REGDUMP_MOD_NUSS = 1, >> >> ++ K3_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, >> >> ++ K3_CPSW_REGDUMP_MOD_MDIO = 3, >> >> ++ K3_CPSW_REGDUMP_MOD_CPSW = 4, >> >> ++ K3_CPSW_REGDUMP_MOD_CPSW_P0 = 5, >> >> ++ K3_CPSW_REGDUMP_MOD_CPSW_PN = 6, >> >> ++ K3_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, >> >> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE = 8, >> >> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, >> >> ++ K3_CPSW_REGDUMP_MOD_LAST, >> >> ++}; >> >> ++ >> >> ++static const char *mod_names[K3_CPSW_REGDUMP_MOD_LAST] = { >> >> ++ [K3_CPSW_REGDUMP_MOD_NUSS] = "cpsw-nuss", >> >> ++ [K3_CPSW_REGDUMP_MOD_RGMII_STATUS] = "cpsw-nuss-rgmii-status", >> >> ++ [K3_CPSW_REGDUMP_MOD_MDIO] = "cpsw-nuss-mdio", >> >> ++ [K3_CPSW_REGDUMP_MOD_CPSW] = "cpsw-nu", >> >> ++ [K3_CPSW_REGDUMP_MOD_CPSW_P0] = "cpsw-nu-p0", >> >> ++ [K3_CPSW_REGDUMP_MOD_CPSW_PN] = "cpsw-nu-pn", >> >> ++ [K3_CPSW_REGDUMP_MOD_CPSW_CPTS] = "cpsw-nu-cpts", >> >> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE] = "cpsw-nu-ale", >> >> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL] = "cpsw-nu-ale-tbl", >> >> ++}; >> >> ++ >> >> ++static void cpsw_ale_dump_oui_entry(int index, u32 *ale_entry) >> >> ++{ >> >> ++ u32 oui_addr; >> >> ++ >> >> ++ oui_addr = cpsw_ale_get_oui_addr(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: OUI Unicast\n, \tOUI = %02x:%02x:%02x\n", >> >> ++ index, (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, >> >> ++ (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, oui_addr & OUI_ADDR_MASK); >> >> ++} >> >> ++ >> >> ++static void cpsw_ale_dump_addr(int index, u32 *ale_entry) >> >> ++{ >> >> ++ u8 addr[NUM_MAC_OCTET]; >> >> ++ >> >> ++ cpsw_ale_get_addr(ale_entry, addr); >> >> ++ >> >> ++ if (cpsw_ale_get_mcast(ale_entry)) { >> >> ++ static const char * const str_mcast_state[] = {"Forwarding", >> >> ++ "Blocking/Forwarding/Learning", >> >> ++ "Learning/Forwarding", >> >> ++ "Forwarding"}; >> >> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >> >> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >> >> ++ u8 super = cpsw_ale_get_super(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: Multicast\n \tAddress = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_State = %s, %sSuper, port_mask = 0x%x\n", >> >> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], >> >> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >> >> ++ } else { >> >> ++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", >> >> ++ "Touched"}; >> >> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >> >> ++ u8 port_num = cpsw_ale_get_port_num(ale_entry); >> >> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >> >> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >> >> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >> >> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: Unicast\n \tUpdated Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast Type = %s, Port_num = 0x%x, Secure: %d, Blocked: %d, Touch = %d, Agable = %d\n", >> >> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], >> >> ++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); >> >> ++ } >> >> ++} >> >> ++ >> >> ++static void cpsw_ale_dump_inner_vlan_entry(int index, u32 *ale_entry) >> >> ++{ >> >> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >> >> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >> >> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: Inner VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", >> >> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, >> >> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); >> >> ++ >> >> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >> >> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", >> >> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >> >> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, >> >> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >> >> ++ >> >> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", >> >> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, >> >> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, >> >> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, >> >> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >> >> ++ } else { >> >> ++ fprintf(stdout, "\tVLAN ID = %d, Registered Mask = 0x%x, No Frag = %d\n", >> >> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >> >> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK, >> >> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK); >> >> ++ >> >> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x, Members = 0x%x\n", >> >> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + >> >> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), >> >> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, >> >> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, >> >> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >> >> ++ } >> >> ++} >> >> ++ >> >> ++static void cpsw_ale_dump_outer_vlan_entry(int index, u32 *ale_entry) >> >> ++{ >> >> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >> >> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >> >> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: Outer VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", >> >> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, >> >> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); >> >> ++ >> >> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >> >> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", >> >> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >> >> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, >> >> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >> >> ++ >> >> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", >> >> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, >> >> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, >> >> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, >> >> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >> >> ++ } else { >> >> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", >> >> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >> >> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK, >> >> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >> >> ++ >> >> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x Members = 0x%x\n", >> >> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + >> >> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), >> >> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, >> >> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, >> >> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >> >> ++ } >> >> ++} >> >> ++ >> >> ++static void cpsw_ale_dump_ethertype_entry(int index, u32 *ale_entry) >> >> ++{ >> >> ++ u16 ethertype = cpsw_ale_get_ethertype(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: VLAN Ethertype\n \tEthertype = 0x%x\n", index, ethertype); >> >> ++} >> >> ++ >> >> ++static void cpsw_ale_dump_ipv4_entry(int index, u32 *ale_entry) >> >> ++{ >> >> ++ u8 ingress_bits = cpsw_ale_get_ingress_bits(ale_entry); >> >> ++ u32 ipv4_addr = cpsw_ale_get_ipv4_addr(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: VLAN IPv4\n \tIngress Bits: 0x%x IPv4 Address = %u.%u.%u.%u\n", >> >> ++ index, ingress_bits, ipv4_addr >> IPV4_ADDR_OCT1_SHIFT & IPV4_ADDR_MASK, >> >> ++ ipv4_addr >> IPV4_ADDR_OCT2_SHIFT & IPV4_ADDR_MASK, >> >> ++ ipv4_addr >> IPV4_ADDR_OCT3_SHIFT & IPV4_ADDR_MASK, ipv4_addr & IPV4_ADDR_MASK); >> >> ++} >> >> ++ >> >> ++static void cpsw_ale_dump_ipv6_entry(int index, u32 *ale_entry) >> >> ++{ >> >> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >> >> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >> >> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >> >> ++ >> >> ++ if (index & IPV6_HIGH_ENTRY_FLAG) { >> >> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Higher Entry (Lower Bit entry at %04u)\n \tIgnored Multicast bits: 0x%x, IPv6 Address (Bits [127:68]) = %04x:%03x%01x:%04x:%03x\n", >> >> ++ index, (index & (~IPV6_HIGH_ENTRY_FLAG)), >> >> ++ vlan_entry_word2 & IPV6_IGNMCBITS_MASK, >> >> ++ (vlan_entry_word1 >> IPV6_HADDR_W1_SHIFT) & IPV6_HADDR_W1_MASK_1, >> >> ++ vlan_entry_word1 & IPV6_HADDR_W1_MASK_2, >> >> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_1) & IPV6_HADDR_W0_MASK_1, >> >> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_2) & IPV6_HADDR_W0_MASK_2, >> >> ++ vlan_entry_word0 & IPV6_HADDR_W0_MASK_2); >> >> ++ } else { >> >> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Lower Entry (Higher Bit entry at %04u)\n \tIPv6 Address (Bits [127:68]) = %01x:%01x%03x:%04x:%04x:%04x\n", >> >> ++ index, (index | IPV6_HIGH_ENTRY_FLAG), >> >> ++ (vlan_entry_word2 >> IPV6_LADDR_W2_SHIFT) & IPV6_LADDR_W2_MAKS, >> >> ++ vlan_entry_word2 & IPV6_LADDR_W2_MAKS, >> >> ++ (vlan_entry_word1 >> IPV6_LADDR_W1_SHIFT) & IPV6_LADDR_W1_MASK_1, >> >> ++ vlan_entry_word1 & IPV6_LADDR_W1_MASK, >> >> ++ (vlan_entry_word0 >> IPV6_LADDR_W0_SHIFT) & IPV6_LADDR_W0_MASK, >> >> ++ vlan_entry_word0 & IPV6_LADDR_W0_MASK); >> >> ++ } >> >> ++} >> >> ++ >> >> ++static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry) >> >> ++{ >> >> ++ u8 addr[NUM_MAC_OCTET]; >> >> ++ int vlan = cpsw_ale_get_vlan_id(ale_entry); >> >> ++ >> >> ++ cpsw_ale_get_addr(ale_entry, addr); >> >> ++ if (cpsw_ale_get_mcast(ale_entry)) { >> >> ++ static const char * const str_mcast_state[] = {"Forwarding", >> >> ++ "Blocking/Forwarding/Learning", >> >> ++ "Learning/Forwarding", >> >> ++ "Forwarding"}; >> >> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >> >> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >> >> ++ u8 super = cpsw_ale_get_super(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: Multicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_state = %s, %s Super, port_mask = 0x%x\n", >> >> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], >> >> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >> >> ++ } else { >> >> ++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", >> >> ++ "Touched"}; >> >> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >> >> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >> >> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >> >> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >> >> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >> >> ++ >> >> ++ int port_num; >> >> ++ >> >> ++ if (rtl_version == CPSW2G_RTL_VERSION) >> >> ++ port_num = cpsw_ale_get_port_num_2g(ale_entry); >> >> ++ else if (rtl_version == CPSW3G_RTL_VERSION) >> >> ++ port_num = cpsw_ale_get_port_num_3g(ale_entry); >> >> ++ else >> >> ++ port_num = cpsw_ale_get_port_num(ale_entry); >> >> ++ >> >> ++ fprintf(stdout, "%d: Type: Unicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast_type = %s, port_num = 0x%x, Secure = %d, Blocked = %d, Touch = %d, Agable = %d\n", >> >> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], >> >> ++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); >> >> ++ } >> >> ++} >> >> ++ >> >> ++void cpsw_dump_ale(struct k3_cpsw_regdump_hdr *ale_hdr, u32 *ale_pos) >> >> ++{ >> >> ++ int i, ale_entries; >> >> ++ >> >> ++ if (!ale_hdr) >> >> ++ return; >> >> ++ >> >> ++ ale_entries = (ale_hdr->len - sizeof(struct k3_cpsw_regdump_hdr)) / >> >> ++ ALE_ENTRY_WORDS / sizeof(u32); >> >> ++ >> >> ++ printf("Number of ALE entries: %d\n", ale_entries); >> >> ++ ale_pos += 2; >> >> ++ for (i = 0; i < ale_entries; i++) { >> >> ++ int type; >> >> ++ >> >> ++ type = cpsw_ale_get_entry_type(ale_pos); >> >> ++ >> >> ++ switch (type) { >> >> ++ case ALE_ENTRY_FREE: >> >> ++ break; >> >> ++ >> >> ++ case ALE_ENTRY_ADDR: >> >> ++ u32 oui_entry = cpsw_ale_get_oui_addr(ale_pos); >> >> ++ >> >> ++ if (oui_entry == 0x2) >> >> ++ cpsw_ale_dump_oui_entry(i, ale_pos); >> >> ++ else >> >> ++ cpsw_ale_dump_addr(i, ale_pos); >> >> ++ break; >> >> ++ >> >> ++ case ALE_ENTRY_VLAN: >> >> ++ u32 vlan_entry_type = cpsw_ale_get_vlan_entry_type(ale_pos); >> >> ++ >> >> ++ if (vlan_entry_type == VLAN_INNER_ENTRY) >> >> ++ cpsw_ale_dump_inner_vlan_entry(i, ale_pos); >> >> ++ else if (vlan_entry_type == VLAN_OUTER_ENTRY) >> >> ++ cpsw_ale_dump_outer_vlan_entry(i, ale_pos); >> >> ++ else if (vlan_entry_type == VLAN_ETHERTYPE_ENTRY) >> >> ++ cpsw_ale_dump_ethertype_entry(i, ale_pos); >> >> ++ else if (vlan_entry_type == VLAN_IPV4_ENTRY) >> >> ++ cpsw_ale_dump_ipv4_entry(i, ale_pos); >> >> ++ else if (vlan_entry_type & VLAN_IPV6_ENTRY_MASK) >> >> ++ cpsw_ale_dump_ipv6_entry(i, ale_pos); >> >> ++ break; >> >> ++ >> >> ++ case ALE_ENTRY_VLAN_ADDR: >> >> ++ cpsw_ale_dump_vlan_addr(i, ale_pos); >> >> ++ break; >> >> ++ >> >> ++ default: >> >> ++ break; >> >> ++ } >> >> ++ >> >> ++ ale_pos += ALE_ENTRY_WORDS; >> >> ++ } >> >> ++} >> >> ++ >> >> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused, >> >> ++ struct ethtool_regs *regs) >> >> ++{ >> >> ++ struct k3_cpsw_regdump_hdr *dump_hdr, *ale_hdr = NULL; >> >> ++ u32 *reg = (u32 *)regs->data, *ale_pos; >> >> ++ u32 mod_id; >> >> ++ int i, regdump_len = info->regdump_len; >> >> ++ >> >> ++ fprintf(stdout, "K3 CPSW dump version: %d, len: %d\n", >> >> ++ regs->version, info->regdump_len); >> >> ++ fprintf(stdout, "(Missing registers in memory space can be considered as zero valued)\n"); >> >> ++ >> >> ++ /* Line break before register dump */ >> >> ++ fprintf(stdout, "--------------------------------------------------------------------\n"); >> >> ++ i = 0; >> >> ++ do { >> >> ++ u32 *tmp, j; >> >> ++ u32 num_items; >> >> ++ >> >> ++ dump_hdr = (struct k3_cpsw_regdump_hdr *)reg; >> >> ++ mod_id = dump_hdr->module_id; >> >> ++ >> >> ++ num_items = dump_hdr->len / sizeof(u32); >> >> ++ >> >> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE) >> >> ++ rtl_version = reg[3] & RTL_VERSION_MASK; >> >> ++ >> >> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { >> >> ++ ale_hdr = dump_hdr; >> >> ++ ale_pos = reg; >> >> ++ break; >> >> ++ } >> >> ++ >> >> ++ fprintf(stdout, "%s regdump: number of Registers:(%d)\n", >> >> ++ mod_names[mod_id], num_items - 2); >> >> ++ tmp = reg; >> >> ++ /* Values are stored in pair as reg_offset-reg_val, hence parse the same way*/ >> >> ++ for (j = 2; j < num_items; j += 2) { >> >> ++ if (tmp[j + 1] != 0x0) >> >> ++ fprintf(stdout, "%08x:reg(%08X)\n", tmp[j], tmp[j + 1]); >> >> ++ } >> >> ++ >> >> ++ reg += num_items; >> >> ++ i += dump_hdr->len; >> >> ++ } while (i < regdump_len); >> >> ++ >> >> ++ /* Adding a boundary in between Register dump and ALE table */ >> >> ++ fprintf(stdout, "--------------------------\n"); >> >> ++ >> >> ++ cpsw_dump_ale(ale_hdr, ale_pos); >> >> ++ >> >> ++ return 0; >> >> ++}; >> >> +diff --git a/ethtool.c b/ethtool.c >> >> +index 3ac15a7..a383eb6 100644 >> >> +--- a/ethtool.c >> >> ++++ b/ethtool.c >> >> +@@ -1162,6 +1162,7 @@ static const struct { >> >> + { "fsl_enetc", fsl_enetc_dump_regs }, >> >> + { "fsl_enetc_vf", fsl_enetc_dump_regs }, >> >> + { "hns3", hns3_dump_regs }, >> >> ++ { "am65-cpsw-nuss", am65_cpsw_dump_regs }, >> >> + }; >> >> + #endif >> >> + >> >> +diff --git a/internal.h b/internal.h >> >> +index 4b994f5..81212b4 100644 >> >> +--- a/internal.h >> >> ++++ b/internal.h >> >> +@@ -410,4 +410,7 @@ int cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); >> >> + /* Microchip Ethernet Controller */ >> >> + int lan743x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); >> >> + >> >> ++/* TI K3 CPSW Ethernet Switch */ >> >> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); >> >> ++ >> >> + #endif /* ETHTOOL_INTERNAL_H__ */ >> >> +-- >> >> +2.34.1 >> >> + >> >> diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >> new file mode 100644 >> index 00000000..3b388151 >> --- /dev/null >> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >> @@ -0,0 +1,4 @@ >> +ETHTOOL_ARAGO = "" >> +ETHTOOL_ARAGO:arago = "ethtool-arago.inc" >> + >> +require ${ETHTOOL_ARAGO} >> -- >> 2.34.1
Denys, Ryan, On 11/07/25 07:04, Aniket Limaye via lists.yoctoproject.org wrote: > > > On 11/07/25 06:02, Denys Dmytriyenko wrote: >> I wonder if the patch itself is malformed - specifically if it has >> windows >> newlines that result in interlaced empty lines in mutt on Linux, as seen >> below. While .inc and .bbappend seem fine. >> > > Chintan, Yeah looks like the patchfile I added was not properly > formatted. I will try resending this one quickly. > Not sure what caused the weird encoding in the first place... Sent v2 here: https://lists.yoctoproject.org/g/meta-arago/message/16282 > Thanks, > Aniket > >> >> On Mon, Jul 07, 2025 at 02:37:20PM +0530, Aniket Limaye via >> lists.yoctoproject.org wrote: >>> Add support for TI K3 CPSW register and ALE table dump through the >>> ethtool userspace utility. >>> >>> Signed-off-by: Aniket Limaye <a-limaye@ti.com> >>> --- >>> .../ethtool/ethtool-arago.inc | 8 + >>> ...k3-cpsw-registers-and-ale-table-dump.patch | 574 ++++++++++++++++++ >>> .../ethtool/ethtool_%.bbappend | 4 + >>> 3 files changed, 586 insertions(+) >>> create mode 100644 >>> meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>> create mode 100644 >>> meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>> create mode 100644 >>> meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>> >>> diff --git >>> a/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>> b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>> new file mode 100644 >>> index 00000000..5fd05a85 >>> --- /dev/null >>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>> @@ -0,0 +1,8 @@ >>> +PR:append = ".arago0" >>> + >>> +FILESEXTRAPATHS:prepend := "${THISDIR}/ethtool:" >>> + >>> +SRC_URI:append = " \ >>> + >>> file://pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch \ >>> + " >>> + >>> diff --git >>> a/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>> new file mode 100644 >>> index 00000000..a14089b4 >>> --- /dev/null >>> +++ >>> b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>> @@ -0,0 +1,574 @@ >>> +From: Chintan Vankar <c-vankar@ti.com> >>> >>> +Subject: [PATCH] pretty: Add support for TI K3 CPSW registers and >>> ALE table dump >>> >>> +Date: Thu, 3 Jul 2025 12:02:46 +0530 >>> >>> + >>> >>> +Add support to dump CPSW registers and ALE table for the CPSW >>> instances on >>> >>> +K3 SoCs that are configured using the am65-cpsw-nuss.c device-driver in >>> >>> +Linux. >>> >>> + >>> >>> +Upstream-Status: Submitted >>> [https://lore.kernel.org/all/20250705134807.3514891-1-c-vankar@ti.com/] >>> >>> +Signed-off-by: Chintan Vankar <c-vankar@ti.com> >>> >>> +--- >>> >>> + Makefile.am | 2 +- >>> >>> + am65-cpsw-nuss.c | 510 +++++++++++++++++++++++++++++++++++++++++++++++ >>> >>> + ethtool.c | 1 + >>> >>> + internal.h | 3 + >>> >>> + 4 files changed, 515 insertions(+), 1 deletion(-) >>> >>> + create mode 100644 am65-cpsw-nuss.c >>> >>> + >>> >>> +diff --git a/Makefile.am b/Makefile.am >>> >>> +index b9e06ad..fe6afcb 100644 >>> >>> +--- a/Makefile.am >>> >>> ++++ b/Makefile.am >>> >>> +@@ -23,7 +23,7 @@ ethtool_SOURCES += \ >>> >>> + smsc911x.c at76c50x-usb.c sfc.c stmmac.c \ >>> >>> + sff-common.c sff-common.h sfpid.c sfpdiag.c \ >>> >>> + ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c \ >>> >>> +- igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c >>> >>> ++ igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c >>> am65-cpsw-nuss.c >>> >>> + endif >>> >>> + >>> >>> + if ENABLE_BASH_COMPLETION >>> >>> +diff --git a/am65-cpsw-nuss.c b/am65-cpsw-nuss.c >>> >>> +new file mode 100644 >>> >>> +index 0000000..de8e3e9 >>> >>> +--- /dev/null >>> >>> ++++ b/am65-cpsw-nuss.c >>> >>> +@@ -0,0 +1,510 @@ >>> >>> ++// SPDX-License-Identifier: GPL-2.0-only OR MIT >>> >>> ++/* Code to dump registers and ALE table for the CPSW instances on >>> K3 SoCs that are configured using >>> >>> ++ * the am65-cpsw-nuss device-driver in Linux. >>> >>> ++ * >>> >>> ++ * Copyright (C) 2025 Texas Instruments >>> >>> ++ * Author: Chintan Vankar <c-vankar@ti.com> >>> >>> ++ */ >>> >>> ++ >>> >>> ++#include <stdio.h> >>> >>> ++#include <string.h> >>> >>> ++ >>> >>> ++#include "internal.h" >>> >>> ++ >>> >>> ++#define ALE_ENTRY_BITS 74 >>> >>> ++#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) >>> >>> ++ >>> >>> ++#define ALE_ENTRY_FREE 0x0 >>> >>> ++#define ALE_ENTRY_ADDR 0x1 >>> >>> ++#define ALE_ENTRY_VLAN 0x2 >>> >>> ++#define ALE_ENTRY_VLAN_ADDR 0x3 >>> >>> ++ >>> >>> ++#define BIT(nr) (1 << (nr)) >>> >>> ++#define BITMASK(bits) (BIT(bits) - 1) >>> >>> ++ >>> >>> ++/* ALE word specifiers */ >>> >>> ++#define NUM_ALE_WORDS 2 >>> >>> ++#define ALE_WORD_LEN 32 >>> >>> ++ >>> >>> ++/* MAC address specifiers */ >>> >>> ++#define MAC_START_BIT 40 >>> >>> ++#define MAC_OCTET_LEN 8 >>> >>> ++#define NUM_MAC_OCTET 6 >>> >>> ++ >>> >>> ++/* RTL version specifiers */ >>> >>> ++#define RTL_VERSION_MASK 0xF800 >>> >>> ++#define CPSW2G_RTL_VERSION 0x3800 >>> >>> ++#define CPSW3G_RTL_VERSION 0x0 >>> >>> ++ >>> >>> ++/* OUI address uses format xx:xx:xx, use OUI shift as 16 bits and >>> MASK as 0xFF to parse the same*/ >>> >>> ++#define OUI_ADDR_SHIFT 16 >>> >>> ++#define OUI_ADDR_MASK 0xFF >>> >>> ++ >>> >>> ++/* VLAN entry specifiers */ >>> >>> ++#define VLAN_INNER_ENTRY 0x0 >>> >>> ++#define VLAN_OUTER_ENTRY 0x2 >>> >>> ++#define VLAN_ETHERTYPE_ENTRY 0x4 >>> >>> ++#define VLAN_IPV4_ENTRY 0x6 >>> >>> ++#define VLAN_IPV6_ENTRY_MASK 0x1 >>> >>> ++ >>> >>> ++/* VLAN Inner/Outer table entry MASKs and SHIFTs*/ >>> >>> ++#define NOLEARN_FLAG_SHIFT 2 >>> >>> ++#define NOLEARN_FLAG_MASK 0x1FF >>> >>> ++#define INGRESS_CHECK_SHIFT 1 >>> >>> ++#define INGRESS_CHECK_MASK 0x1 >>> >>> ++#define VLAN_ID_SHIFT 16 >>> >>> ++#define VLAN_ID_MASK 0xFFF >>> >>> ++#define NOFRAG_FLAG_SHIFT_2G 12 >>> >>> ++#define NOFRAG_FLAG_MASK_2G 0x1 >>> >>> ++#define NOFRAG_FLAG_SHIFT 15 >>> >>> ++#define NOFRAG_FLAG_MASK 0x1 >>> >>> ++#define REG_MASK_SHIFT 4 >>> >>> ++#define REG_MASK_MASK 0x1FF >>> >>> ++#define PKT_EGRESS_W1_MASK 0x1 >>> >>> ++#define PKT_EGRESS_W1_OFFSET 512 >>> >>> ++#define PKT_EGRESS_SHIFT 24 >>> >>> ++#define PKT_EGRESS_MASK_2G 0x3 >>> >>> ++#define PKT_EGRESS_MASK 0x1FF >>> >>> ++#define UNREG_MASK_SHIFT_2G 20 >>> >>> ++#define UNREG_MASK_MASK_2G 0x7 >>> >>> ++#define UNREG_MASK_SHIFT 12 >>> >>> ++#define UNREG_MASK_MASK 0x1FF >>> >>> ++#define NXT_HDR_CTRL_SHIFT_2G 19 >>> >>> ++#define NXT_HDR_CTRL_MASK_2G 0x1 >>> >>> ++#define NXT_HDR_CTRL_SHIFT 23 >>> >>> ++#define NXT_HDR_CTRL_MASK 0x1 >>> >>> ++#define VLAN_MEMBER_LIST_MASK_2G 0x3 >>> >>> ++#define VLAN_MEMBER_LIST_MASK 0x1FF >>> >>> ++ >>> >>> ++/* VLAN IPv4 entry MASKs and SHIFTs*/ >>> >>> ++#define IPV4_ADDR_OCT1_SHIFT 24 >>> >>> ++#define IPV4_ADDR_OCT2_SHIFT 16 >>> >>> ++#define IPV4_ADDR_OCT3_SHIFT 8 >>> >>> ++#define IPV4_ADDR_MASK 0xFF >>> >>> ++ >>> >>> ++/* VLAN IPv6 entry MASKs and SHIFTs*/ >>> >>> ++#define IPV6_HIGH_ENTRY_FLAG 0x40 >>> >>> ++#define IPV6_IGNMCBITS_MASK 0xFF >>> >>> ++#define IPV6_HADDR_W1_SHIFT 12 >>> >>> ++#define IPV6_HADDR_W1_MASK_1 0xFFFF >>> >>> ++#define IPV6_HADDR_W1_MASK_2 0xFFF >>> >>> ++#define IPV6_HADDR_W0_SHIFT_1 28 >>> >>> ++#define IPV6_HADDR_W0_MASK_1 0xF >>> >>> ++#define IPV6_HADDR_W0_SHIFT_2 12 >>> >>> ++#define IPV6_HADDR_W0_MASK_2 0xFFFF >>> >>> ++#define IPV6_LADDR_W2_SHIFT 4 >>> >>> ++#define IPV6_LADDR_W2_MAKS 0xF >>> >>> ++#define IPV6_LADDR_W1_SHIFT 16 >>> >>> ++#define IPV6_LADDR_W1_MASK_1 0xFFF >>> >>> ++#define IPV6_LADDR_W1_MASK 0xFFFF >>> >>> ++#define IPV6_LADDR_W0_SHIFT 16 >>> >>> ++#define IPV6_LADDR_W0_MASK 0xFFFF >>> >>> ++ >>> >>> ++/** >>> >>> ++ * Since there are different instances of CPSW (namely cpsw2g, >>> cpsw3g, cpsw5g and cpsw9g) >>> >>> ++ * some register offsets differ to get some parameters for ALE >>> table, parse rtl_version >>> >>> ++ * from ALE_MOD_VER register to determine which instance is being >>> used. >>> >>> ++ */ >>> >>> ++u32 rtl_version; >>> >>> ++ >>> >>> ++static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 >>> bits) >>> >>> ++{ >>> >>> ++ int idx; >>> >>> ++ >>> >>> ++ idx = start / ALE_WORD_LEN; >>> >>> ++ start -= idx * ALE_WORD_LEN; >>> >>> ++ >>> >>> ++ /** >>> >>> ++ * ALE words are stored in order word2, word1 and word0, flip >>> the word to parse in numeric >>> >>> ++ * order >>> >>> ++ */ >>> >>> ++ idx = NUM_ALE_WORDS - idx; /* flip */ >>> >>> ++ return (ale_entry[idx] >> start) & BITMASK(bits); >>> >>> ++} >>> >>> ++ >>> >>> ++#define DEFINE_ALE_FIELD(name, start, bits) \ >>> >>> ++static inline int cpsw_ale_get_##name(u32 *ale_entry) \ >>> >>> ++{ \ >>> >>> ++ return cpsw_ale_get_field(ale_entry, start, bits); \ >>> >>> ++} >>> >>> ++ >>> >>> ++DEFINE_ALE_FIELD(entry_type, 60, 2) >>> >>> ++DEFINE_ALE_FIELD(vlan_id, 48, 12) >>> >>> ++DEFINE_ALE_FIELD(mcast_state, 62, 2) >>> >>> ++DEFINE_ALE_FIELD(port_mask, 66, 9) >>> >>> ++DEFINE_ALE_FIELD(super, 65, 1) >>> >>> ++DEFINE_ALE_FIELD(agable, 62, 1) >>> >>> ++DEFINE_ALE_FIELD(touched, 63, 1) >>> >>> ++DEFINE_ALE_FIELD(ucast_type, 62, 2) >>> >>> ++DEFINE_ALE_FIELD(port_num, 66, 4) >>> >>> ++DEFINE_ALE_FIELD(port_num_2g, 66, 1) >>> >>> ++DEFINE_ALE_FIELD(port_num_3g, 66, 2) >>> >>> ++DEFINE_ALE_FIELD(blocked, 65, 1) >>> >>> ++DEFINE_ALE_FIELD(secure, 64, 1) >>> >>> ++DEFINE_ALE_FIELD(oui_entry, 62, 2) >>> >>> ++DEFINE_ALE_FIELD(oui_addr, 4, 24) >>> >>> ++DEFINE_ALE_FIELD(mcast, 40, 1) >>> >>> ++DEFINE_ALE_FIELD(vlan_entry_type, 62, 3) >>> >>> ++DEFINE_ALE_FIELD(ethertype, 0, 16) >>> >>> ++DEFINE_ALE_FIELD(ipv4_addr, 0, 32) >>> >>> ++DEFINE_ALE_FIELD(ingress_bits, 65, 5) >>> >>> ++DEFINE_ALE_FIELD(ipv6_addr_low, 0, 60) >>> >>> ++DEFINE_ALE_FIELD(ipv6_addr_mid, 63, 8) >>> >>> ++DEFINE_ALE_FIELD(ipv6_addr_high, 0, 60) >>> >>> ++DEFINE_ALE_FIELD(entry_word0, 0, 32) >>> >>> ++DEFINE_ALE_FIELD(entry_word1, 32, 32) >>> >>> ++DEFINE_ALE_FIELD(entry_word2, 64, 12) >>> >>> ++ >>> >>> ++static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) >>> >>> ++{ >>> >>> ++ int i; >>> >>> ++ >>> >>> ++ for (i = 0; i < NUM_MAC_OCTET; i++) >>> >>> ++ addr[i] = cpsw_ale_get_field(ale_entry, MAC_START_BIT - >>> MAC_OCTET_LEN * i, >>> >>> ++ MAC_OCTET_LEN); >>> >>> ++} >>> >>> ++ >>> >>> ++struct k3_cpsw_regdump_hdr { >>> >>> ++ u32 module_id; >>> >>> ++ u32 len; >>> >>> ++}; >>> >>> ++ >>> >>> ++enum { >>> >>> ++ K3_CPSW_REGDUMP_MOD_NUSS = 1, >>> >>> ++ K3_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, >>> >>> ++ K3_CPSW_REGDUMP_MOD_MDIO = 3, >>> >>> ++ K3_CPSW_REGDUMP_MOD_CPSW = 4, >>> >>> ++ K3_CPSW_REGDUMP_MOD_CPSW_P0 = 5, >>> >>> ++ K3_CPSW_REGDUMP_MOD_CPSW_PN = 6, >>> >>> ++ K3_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, >>> >>> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE = 8, >>> >>> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, >>> >>> ++ K3_CPSW_REGDUMP_MOD_LAST, >>> >>> ++}; >>> >>> ++ >>> >>> ++static const char *mod_names[K3_CPSW_REGDUMP_MOD_LAST] = { >>> >>> ++ [K3_CPSW_REGDUMP_MOD_NUSS] = "cpsw-nuss", >>> >>> ++ [K3_CPSW_REGDUMP_MOD_RGMII_STATUS] = "cpsw-nuss-rgmii-status", >>> >>> ++ [K3_CPSW_REGDUMP_MOD_MDIO] = "cpsw-nuss-mdio", >>> >>> ++ [K3_CPSW_REGDUMP_MOD_CPSW] = "cpsw-nu", >>> >>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_P0] = "cpsw-nu-p0", >>> >>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_PN] = "cpsw-nu-pn", >>> >>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_CPTS] = "cpsw-nu-cpts", >>> >>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE] = "cpsw-nu-ale", >>> >>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL] = "cpsw-nu-ale-tbl", >>> >>> ++}; >>> >>> ++ >>> >>> ++static void cpsw_ale_dump_oui_entry(int index, u32 *ale_entry) >>> >>> ++{ >>> >>> ++ u32 oui_addr; >>> >>> ++ >>> >>> ++ oui_addr = cpsw_ale_get_oui_addr(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: OUI Unicast\n, \tOUI = >>> %02x:%02x:%02x\n", >>> >>> ++ index, (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, >>> >>> ++ (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, oui_addr & >>> OUI_ADDR_MASK); >>> >>> ++} >>> >>> ++ >>> >>> ++static void cpsw_ale_dump_addr(int index, u32 *ale_entry) >>> >>> ++{ >>> >>> ++ u8 addr[NUM_MAC_OCTET]; >>> >>> ++ >>> >>> ++ cpsw_ale_get_addr(ale_entry, addr); >>> >>> ++ >>> >>> ++ if (cpsw_ale_get_mcast(ale_entry)) { >>> >>> ++ static const char * const str_mcast_state[] = {"Forwarding", >>> >>> ++ "Blocking/Forwarding/Learning", >>> >>> ++ "Learning/Forwarding", >>> >>> ++ "Forwarding"}; >>> >>> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >>> >>> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >>> >>> ++ u8 super = cpsw_ale_get_super(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: Multicast\n \tAddress = >>> %02x:%02x:%02x:%02x:%02x:%02x, Multicast_State = %s, %sSuper, >>> port_mask = 0x%x\n", >>> >>> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], >>> addr[5], >>> >>> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >>> >>> ++ } else { >>> >>> ++ static const char * const s_ucast_type[] = {"Persistent", >>> "Untouched", "OUI", >>> >>> ++ "Touched"}; >>> >>> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >>> >>> ++ u8 port_num = cpsw_ale_get_port_num(ale_entry); >>> >>> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >>> >>> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >>> >>> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >>> >>> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: Unicast\n \tUpdated Address = >>> %02x:%02x:%02x:%02x:%02x:%02x, Unicast Type = %s, Port_num = 0x%x, >>> Secure: %d, Blocked: %d, Touch = %d, Agable = %d\n", >>> >>> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], >>> addr[5], >>> >>> ++ s_ucast_type[ucast_type], port_num, secure, blocked, >>> touched, agable); >>> >>> ++ } >>> >>> ++} >>> >>> ++ >>> >>> ++static void cpsw_ale_dump_inner_vlan_entry(int index, u32 *ale_entry) >>> >>> ++{ >>> >>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>> >>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>> >>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: Inner VLAN\n \tNolearn Mask = 0x%x, >>> Ingress Check = %d\n", >>> >>> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & >>> NOLEARN_FLAG_MASK, >>> >>> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & >>> INGRESS_CHECK_MASK); >>> >>> ++ >>> >>> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >>> >>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered >>> Mask = 0x%x\n", >>> >>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>> >>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & >>> NOFRAG_FLAG_MASK_2G, >>> >>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>> >>> ++ >>> >>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>> Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = >>> 0x%x\n", >>> >>> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>> PKT_EGRESS_MASK_2G, >>> >>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & >>> UNREG_MASK_MASK_2G, >>> >>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & >>> NXT_HDR_CTRL_MASK_2G, >>> >>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >>> >>> ++ } else { >>> >>> ++ fprintf(stdout, "\tVLAN ID = %d, Registered Mask = 0x%x, No >>> Frag = %d\n", >>> >>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>> >>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK, >>> >>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & >>> NOFRAG_FLAG_MASK); >>> >>> ++ >>> >>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>> Limit Next Header Control = %d, Unregistered Mask = 0x%x, Members = >>> 0x%x\n", >>> >>> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * >>> PKT_EGRESS_W1_OFFSET + >>> >>> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>> PKT_EGRESS_MASK), >>> >>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & >>> NXT_HDR_CTRL_MASK, >>> >>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, >>> >>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >>> >>> ++ } >>> >>> ++} >>> >>> ++ >>> >>> ++static void cpsw_ale_dump_outer_vlan_entry(int index, u32 *ale_entry) >>> >>> ++{ >>> >>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>> >>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>> >>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: Outer VLAN\n \tNolearn Mask = 0x%x, >>> Ingress Check = %d\n", >>> >>> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & >>> NOLEARN_FLAG_MASK, >>> >>> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & >>> INGRESS_CHECK_MASK); >>> >>> ++ >>> >>> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >>> >>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered >>> Mask = 0x%x\n", >>> >>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>> >>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & >>> NOFRAG_FLAG_MASK_2G, >>> >>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>> >>> ++ >>> >>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>> Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = >>> 0x%x\n", >>> >>> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>> PKT_EGRESS_MASK_2G, >>> >>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & >>> UNREG_MASK_MASK_2G, >>> >>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & >>> NXT_HDR_CTRL_MASK_2G, >>> >>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >>> >>> ++ } else { >>> >>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered >>> Mask = 0x%x\n", >>> >>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>> >>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & >>> NOFRAG_FLAG_MASK, >>> >>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>> >>> ++ >>> >>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>> Limit Next Header Control = %d, Unregistered Mask = 0x%x Members = >>> 0x%x\n", >>> >>> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * >>> PKT_EGRESS_W1_OFFSET + >>> >>> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>> PKT_EGRESS_MASK), >>> >>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & >>> NXT_HDR_CTRL_MASK, >>> >>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, >>> >>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >>> >>> ++ } >>> >>> ++} >>> >>> ++ >>> >>> ++static void cpsw_ale_dump_ethertype_entry(int index, u32 *ale_entry) >>> >>> ++{ >>> >>> ++ u16 ethertype = cpsw_ale_get_ethertype(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: VLAN Ethertype\n \tEthertype = >>> 0x%x\n", index, ethertype); >>> >>> ++} >>> >>> ++ >>> >>> ++static void cpsw_ale_dump_ipv4_entry(int index, u32 *ale_entry) >>> >>> ++{ >>> >>> ++ u8 ingress_bits = cpsw_ale_get_ingress_bits(ale_entry); >>> >>> ++ u32 ipv4_addr = cpsw_ale_get_ipv4_addr(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: VLAN IPv4\n \tIngress Bits: 0x%x >>> IPv4 Address = %u.%u.%u.%u\n", >>> >>> ++ index, ingress_bits, ipv4_addr >> IPV4_ADDR_OCT1_SHIFT & >>> IPV4_ADDR_MASK, >>> >>> ++ ipv4_addr >> IPV4_ADDR_OCT2_SHIFT & IPV4_ADDR_MASK, >>> >>> ++ ipv4_addr >> IPV4_ADDR_OCT3_SHIFT & IPV4_ADDR_MASK, >>> ipv4_addr & IPV4_ADDR_MASK); >>> >>> ++} >>> >>> ++ >>> >>> ++static void cpsw_ale_dump_ipv6_entry(int index, u32 *ale_entry) >>> >>> ++{ >>> >>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>> >>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>> >>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>> >>> ++ >>> >>> ++ if (index & IPV6_HIGH_ENTRY_FLAG) { >>> >>> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Higher Entry (Lower >>> Bit entry at %04u)\n \tIgnored Multicast bits: 0x%x, IPv6 Address >>> (Bits [127:68]) = %04x:%03x%01x:%04x:%03x\n", >>> >>> ++ index, (index & (~IPV6_HIGH_ENTRY_FLAG)), >>> >>> ++ vlan_entry_word2 & IPV6_IGNMCBITS_MASK, >>> >>> ++ (vlan_entry_word1 >> IPV6_HADDR_W1_SHIFT) & >>> IPV6_HADDR_W1_MASK_1, >>> >>> ++ vlan_entry_word1 & IPV6_HADDR_W1_MASK_2, >>> >>> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_1) & >>> IPV6_HADDR_W0_MASK_1, >>> >>> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_2) & >>> IPV6_HADDR_W0_MASK_2, >>> >>> ++ vlan_entry_word0 & IPV6_HADDR_W0_MASK_2); >>> >>> ++ } else { >>> >>> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Lower Entry (Higher >>> Bit entry at %04u)\n \tIPv6 Address (Bits [127:68]) = >>> %01x:%01x%03x:%04x:%04x:%04x\n", >>> >>> ++ index, (index | IPV6_HIGH_ENTRY_FLAG), >>> >>> ++ (vlan_entry_word2 >> IPV6_LADDR_W2_SHIFT) & >>> IPV6_LADDR_W2_MAKS, >>> >>> ++ vlan_entry_word2 & IPV6_LADDR_W2_MAKS, >>> >>> ++ (vlan_entry_word1 >> IPV6_LADDR_W1_SHIFT) & >>> IPV6_LADDR_W1_MASK_1, >>> >>> ++ vlan_entry_word1 & IPV6_LADDR_W1_MASK, >>> >>> ++ (vlan_entry_word0 >> IPV6_LADDR_W0_SHIFT) & >>> IPV6_LADDR_W0_MASK, >>> >>> ++ vlan_entry_word0 & IPV6_LADDR_W0_MASK); >>> >>> ++ } >>> >>> ++} >>> >>> ++ >>> >>> ++static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry) >>> >>> ++{ >>> >>> ++ u8 addr[NUM_MAC_OCTET]; >>> >>> ++ int vlan = cpsw_ale_get_vlan_id(ale_entry); >>> >>> ++ >>> >>> ++ cpsw_ale_get_addr(ale_entry, addr); >>> >>> ++ if (cpsw_ale_get_mcast(ale_entry)) { >>> >>> ++ static const char * const str_mcast_state[] = {"Forwarding", >>> >>> ++ "Blocking/Forwarding/Learning", >>> >>> ++ "Learning/Forwarding", >>> >>> ++ "Forwarding"}; >>> >>> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >>> >>> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >>> >>> ++ u8 super = cpsw_ale_get_super(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: Multicast\n \tVID = %d, Address >>> = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_state = %s, %s Super, >>> port_mask = 0x%x\n", >>> >>> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], >>> addr[4], addr[5], >>> >>> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >>> >>> ++ } else { >>> >>> ++ static const char * const s_ucast_type[] = {"Persistent", >>> "Untouched", "OUI", >>> >>> ++ "Touched"}; >>> >>> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >>> >>> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >>> >>> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >>> >>> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >>> >>> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >>> >>> ++ >>> >>> ++ int port_num; >>> >>> ++ >>> >>> ++ if (rtl_version == CPSW2G_RTL_VERSION) >>> >>> ++ port_num = cpsw_ale_get_port_num_2g(ale_entry); >>> >>> ++ else if (rtl_version == CPSW3G_RTL_VERSION) >>> >>> ++ port_num = cpsw_ale_get_port_num_3g(ale_entry); >>> >>> ++ else >>> >>> ++ port_num = cpsw_ale_get_port_num(ale_entry); >>> >>> ++ >>> >>> ++ fprintf(stdout, "%d: Type: Unicast\n \tVID = %d, Address = >>> %02x:%02x:%02x:%02x:%02x:%02x, Unicast_type = %s, port_num = 0x%x, >>> Secure = %d, Blocked = %d, Touch = %d, Agable = %d\n", >>> >>> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], >>> addr[4], addr[5], >>> >>> ++ s_ucast_type[ucast_type], port_num, secure, blocked, >>> touched, agable); >>> >>> ++ } >>> >>> ++} >>> >>> ++ >>> >>> ++void cpsw_dump_ale(struct k3_cpsw_regdump_hdr *ale_hdr, u32 *ale_pos) >>> >>> ++{ >>> >>> ++ int i, ale_entries; >>> >>> ++ >>> >>> ++ if (!ale_hdr) >>> >>> ++ return; >>> >>> ++ >>> >>> ++ ale_entries = (ale_hdr->len - sizeof(struct >>> k3_cpsw_regdump_hdr)) / >>> >>> ++ ALE_ENTRY_WORDS / sizeof(u32); >>> >>> ++ >>> >>> ++ printf("Number of ALE entries: %d\n", ale_entries); >>> >>> ++ ale_pos += 2; >>> >>> ++ for (i = 0; i < ale_entries; i++) { >>> >>> ++ int type; >>> >>> ++ >>> >>> ++ type = cpsw_ale_get_entry_type(ale_pos); >>> >>> ++ >>> >>> ++ switch (type) { >>> >>> ++ case ALE_ENTRY_FREE: >>> >>> ++ break; >>> >>> ++ >>> >>> ++ case ALE_ENTRY_ADDR: >>> >>> ++ u32 oui_entry = cpsw_ale_get_oui_addr(ale_pos); >>> >>> ++ >>> >>> ++ if (oui_entry == 0x2) >>> >>> ++ cpsw_ale_dump_oui_entry(i, ale_pos); >>> >>> ++ else >>> >>> ++ cpsw_ale_dump_addr(i, ale_pos); >>> >>> ++ break; >>> >>> ++ >>> >>> ++ case ALE_ENTRY_VLAN: >>> >>> ++ u32 vlan_entry_type = >>> cpsw_ale_get_vlan_entry_type(ale_pos); >>> >>> ++ >>> >>> ++ if (vlan_entry_type == VLAN_INNER_ENTRY) >>> >>> ++ cpsw_ale_dump_inner_vlan_entry(i, ale_pos); >>> >>> ++ else if (vlan_entry_type == VLAN_OUTER_ENTRY) >>> >>> ++ cpsw_ale_dump_outer_vlan_entry(i, ale_pos); >>> >>> ++ else if (vlan_entry_type == VLAN_ETHERTYPE_ENTRY) >>> >>> ++ cpsw_ale_dump_ethertype_entry(i, ale_pos); >>> >>> ++ else if (vlan_entry_type == VLAN_IPV4_ENTRY) >>> >>> ++ cpsw_ale_dump_ipv4_entry(i, ale_pos); >>> >>> ++ else if (vlan_entry_type & VLAN_IPV6_ENTRY_MASK) >>> >>> ++ cpsw_ale_dump_ipv6_entry(i, ale_pos); >>> >>> ++ break; >>> >>> ++ >>> >>> ++ case ALE_ENTRY_VLAN_ADDR: >>> >>> ++ cpsw_ale_dump_vlan_addr(i, ale_pos); >>> >>> ++ break; >>> >>> ++ >>> >>> ++ default: >>> >>> ++ break; >>> >>> ++ } >>> >>> ++ >>> >>> ++ ale_pos += ALE_ENTRY_WORDS; >>> >>> ++ } >>> >>> ++} >>> >>> ++ >>> >>> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused, >>> >>> ++ struct ethtool_regs *regs) >>> >>> ++{ >>> >>> ++ struct k3_cpsw_regdump_hdr *dump_hdr, *ale_hdr = NULL; >>> >>> ++ u32 *reg = (u32 *)regs->data, *ale_pos; >>> >>> ++ u32 mod_id; >>> >>> ++ int i, regdump_len = info->regdump_len; >>> >>> ++ >>> >>> ++ fprintf(stdout, "K3 CPSW dump version: %d, len: %d\n", >>> >>> ++ regs->version, info->regdump_len); >>> >>> ++ fprintf(stdout, "(Missing registers in memory space can be >>> considered as zero valued)\n"); >>> >>> ++ >>> >>> ++ /* Line break before register dump */ >>> >>> ++ fprintf(stdout, >>> "--------------------------------------------------------------------\n"); >>> >>> ++ i = 0; >>> >>> ++ do { >>> >>> ++ u32 *tmp, j; >>> >>> ++ u32 num_items; >>> >>> ++ >>> >>> ++ dump_hdr = (struct k3_cpsw_regdump_hdr *)reg; >>> >>> ++ mod_id = dump_hdr->module_id; >>> >>> ++ >>> >>> ++ num_items = dump_hdr->len / sizeof(u32); >>> >>> ++ >>> >>> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE) >>> >>> ++ rtl_version = reg[3] & RTL_VERSION_MASK; >>> >>> ++ >>> >>> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { >>> >>> ++ ale_hdr = dump_hdr; >>> >>> ++ ale_pos = reg; >>> >>> ++ break; >>> >>> ++ } >>> >>> ++ >>> >>> ++ fprintf(stdout, "%s regdump: number of Registers:(%d)\n", >>> >>> ++ mod_names[mod_id], num_items - 2); >>> >>> ++ tmp = reg; >>> >>> ++ /* Values are stored in pair as reg_offset-reg_val, hence >>> parse the same way*/ >>> >>> ++ for (j = 2; j < num_items; j += 2) { >>> >>> ++ if (tmp[j + 1] != 0x0) >>> >>> ++ fprintf(stdout, "%08x:reg(%08X)\n", tmp[j], tmp[j + >>> 1]); >>> >>> ++ } >>> >>> ++ >>> >>> ++ reg += num_items; >>> >>> ++ i += dump_hdr->len; >>> >>> ++ } while (i < regdump_len); >>> >>> ++ >>> >>> ++ /* Adding a boundary in between Register dump and ALE table */ >>> >>> ++ fprintf(stdout, "--------------------------\n"); >>> >>> ++ >>> >>> ++ cpsw_dump_ale(ale_hdr, ale_pos); >>> >>> ++ >>> >>> ++ return 0; >>> >>> ++}; >>> >>> +diff --git a/ethtool.c b/ethtool.c >>> >>> +index 3ac15a7..a383eb6 100644 >>> >>> +--- a/ethtool.c >>> >>> ++++ b/ethtool.c >>> >>> +@@ -1162,6 +1162,7 @@ static const struct { >>> >>> + { "fsl_enetc", fsl_enetc_dump_regs }, >>> >>> + { "fsl_enetc_vf", fsl_enetc_dump_regs }, >>> >>> + { "hns3", hns3_dump_regs }, >>> >>> ++ { "am65-cpsw-nuss", am65_cpsw_dump_regs }, >>> >>> + }; >>> >>> + #endif >>> >>> + >>> >>> +diff --git a/internal.h b/internal.h >>> >>> +index 4b994f5..81212b4 100644 >>> >>> +--- a/internal.h >>> >>> ++++ b/internal.h >>> >>> +@@ -410,4 +410,7 @@ int cpsw_dump_regs(struct ethtool_drvinfo *info, >>> struct ethtool_regs *regs); >>> >>> + /* Microchip Ethernet Controller */ >>> >>> + int lan743x_dump_regs(struct ethtool_drvinfo *info, struct >>> ethtool_regs *regs); >>> >>> + >>> >>> ++/* TI K3 CPSW Ethernet Switch */ >>> >>> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info, struct >>> ethtool_regs *regs); >>> >>> ++ >>> >>> + #endif /* ETHTOOL_INTERNAL_H__ */ >>> >>> +-- >>> >>> +2.34.1 >>> >>> + >>> >>> diff --git >>> a/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>> b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>> new file mode 100644 >>> index 00000000..3b388151 >>> --- /dev/null >>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>> @@ -0,0 +1,4 @@ >>> +ETHTOOL_ARAGO = "" >>> +ETHTOOL_ARAGO:arago = "ethtool-arago.inc" >>> + >>> +require ${ETHTOOL_ARAGO} >>> -- >>> 2.34.1 > > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#16281): > https://lists.yoctoproject.org/g/meta-arago/message/16281 > Mute This Topic: https://lists.yoctoproject.org/mt/114024756/6607860 > Group Owner: meta-arago+owner@lists.yoctoproject.org > Unsubscribe: https://lists.yoctoproject.org/g/meta-arago/unsub > [a-limaye@ti.com] > -=-=-=-=-=-=-=-=-=-=-=- > >
On 7/10/2025 9:35 PM, Aniket Limaye wrote: > Denys, Ryan, > > On 11/07/25 07:04, Aniket Limaye via lists.yoctoproject.org wrote: >> >> >> On 11/07/25 06:02, Denys Dmytriyenko wrote: >>> I wonder if the patch itself is malformed - specifically if it has >>> windows >>> newlines that result in interlaced empty lines in mutt on Linux, as seen >>> below. While .inc and .bbappend seem fine. >>> >> >> Chintan, Yeah looks like the patchfile I added was not properly >> formatted. I will try resending this one quickly. >> > > Not sure what caused the weird encoding in the first place... > > Sent v2 here: https://lists.yoctoproject.org/g/meta-arago/message/16282 What's really odd is that applying the v1 patch resulted in a perfectly fine file in the repo. I applied this patch yesterday and the patch file looks fine. Or am I wrong. The issue is that this patch is already on next and is going through CICD promotion right now. If this is a problem we may need to submit a follow on patch to fix it. Can someone check the current file in the repo and verify? > >> Thanks, >> Aniket >> >>> >>> On Mon, Jul 07, 2025 at 02:37:20PM +0530, Aniket Limaye via >>> lists.yoctoproject.org wrote: >>>> Add support for TI K3 CPSW register and ALE table dump through the >>>> ethtool userspace utility. >>>> >>>> Signed-off-by: Aniket Limaye <a-limaye@ti.com> >>>> --- >>>> .../ethtool/ethtool-arago.inc | 8 + >>>> ...k3-cpsw-registers-and-ale-table-dump.patch | 574 >>>> ++++++++++++++++++ >>>> .../ethtool/ethtool_%.bbappend | 4 + >>>> 3 files changed, 586 insertions(+) >>>> create mode 100644 >>>> meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>> create mode 100644 >>>> meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>> create mode 100644 >>>> meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>> >>>> diff --git >>>> a/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>> b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>> new file mode 100644 >>>> index 00000000..5fd05a85 >>>> --- /dev/null >>>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>> @@ -0,0 +1,8 @@ >>>> +PR:append = ".arago0" >>>> + >>>> +FILESEXTRAPATHS:prepend := "${THISDIR}/ethtool:" >>>> + >>>> +SRC_URI:append = " \ >>>> + >>>> file://pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch \ >>>> + " >>>> + >>>> diff --git >>>> a/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>> new file mode 100644 >>>> index 00000000..a14089b4 >>>> --- /dev/null >>>> +++ >>>> b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>> @@ -0,0 +1,574 @@ >>>> +From: Chintan Vankar <c-vankar@ti.com> >>>> >>>> +Subject: [PATCH] pretty: Add support for TI K3 CPSW registers and >>>> ALE table dump >>>> >>>> +Date: Thu, 3 Jul 2025 12:02:46 +0530 >>>> >>>> + >>>> >>>> +Add support to dump CPSW registers and ALE table for the CPSW >>>> instances on >>>> >>>> +K3 SoCs that are configured using the am65-cpsw-nuss.c >>>> device-driver in >>>> >>>> +Linux. >>>> >>>> + >>>> >>>> +Upstream-Status: Submitted >>>> [https://lore.kernel.org/all/20250705134807.3514891-1-c-vankar@ti.com/] >>>> >>>> +Signed-off-by: Chintan Vankar <c-vankar@ti.com> >>>> >>>> +--- >>>> >>>> + Makefile.am | 2 +- >>>> >>>> + am65-cpsw-nuss.c | 510 >>>> +++++++++++++++++++++++++++++++++++++++++++++++ >>>> >>>> + ethtool.c | 1 + >>>> >>>> + internal.h | 3 + >>>> >>>> + 4 files changed, 515 insertions(+), 1 deletion(-) >>>> >>>> + create mode 100644 am65-cpsw-nuss.c >>>> >>>> + >>>> >>>> +diff --git a/Makefile.am b/Makefile.am >>>> >>>> +index b9e06ad..fe6afcb 100644 >>>> >>>> +--- a/Makefile.am >>>> >>>> ++++ b/Makefile.am >>>> >>>> +@@ -23,7 +23,7 @@ ethtool_SOURCES += \ >>>> >>>> + smsc911x.c at76c50x-usb.c sfc.c stmmac.c \ >>>> >>>> + sff-common.c sff-common.h sfpid.c sfpdiag.c \ >>>> >>>> + ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c \ >>>> >>>> +- igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c >>>> >>>> ++ igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c >>>> am65-cpsw-nuss.c >>>> >>>> + endif >>>> >>>> + >>>> >>>> + if ENABLE_BASH_COMPLETION >>>> >>>> +diff --git a/am65-cpsw-nuss.c b/am65-cpsw-nuss.c >>>> >>>> +new file mode 100644 >>>> >>>> +index 0000000..de8e3e9 >>>> >>>> +--- /dev/null >>>> >>>> ++++ b/am65-cpsw-nuss.c >>>> >>>> +@@ -0,0 +1,510 @@ >>>> >>>> ++// SPDX-License-Identifier: GPL-2.0-only OR MIT >>>> >>>> ++/* Code to dump registers and ALE table for the CPSW instances on >>>> K3 SoCs that are configured using >>>> >>>> ++ * the am65-cpsw-nuss device-driver in Linux. >>>> >>>> ++ * >>>> >>>> ++ * Copyright (C) 2025 Texas Instruments >>>> >>>> ++ * Author: Chintan Vankar <c-vankar@ti.com> >>>> >>>> ++ */ >>>> >>>> ++ >>>> >>>> ++#include <stdio.h> >>>> >>>> ++#include <string.h> >>>> >>>> ++ >>>> >>>> ++#include "internal.h" >>>> >>>> ++ >>>> >>>> ++#define ALE_ENTRY_BITS 74 >>>> >>>> ++#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) >>>> >>>> ++ >>>> >>>> ++#define ALE_ENTRY_FREE 0x0 >>>> >>>> ++#define ALE_ENTRY_ADDR 0x1 >>>> >>>> ++#define ALE_ENTRY_VLAN 0x2 >>>> >>>> ++#define ALE_ENTRY_VLAN_ADDR 0x3 >>>> >>>> ++ >>>> >>>> ++#define BIT(nr) (1 << (nr)) >>>> >>>> ++#define BITMASK(bits) (BIT(bits) - 1) >>>> >>>> ++ >>>> >>>> ++/* ALE word specifiers */ >>>> >>>> ++#define NUM_ALE_WORDS 2 >>>> >>>> ++#define ALE_WORD_LEN 32 >>>> >>>> ++ >>>> >>>> ++/* MAC address specifiers */ >>>> >>>> ++#define MAC_START_BIT 40 >>>> >>>> ++#define MAC_OCTET_LEN 8 >>>> >>>> ++#define NUM_MAC_OCTET 6 >>>> >>>> ++ >>>> >>>> ++/* RTL version specifiers */ >>>> >>>> ++#define RTL_VERSION_MASK 0xF800 >>>> >>>> ++#define CPSW2G_RTL_VERSION 0x3800 >>>> >>>> ++#define CPSW3G_RTL_VERSION 0x0 >>>> >>>> ++ >>>> >>>> ++/* OUI address uses format xx:xx:xx, use OUI shift as 16 bits and >>>> MASK as 0xFF to parse the same*/ >>>> >>>> ++#define OUI_ADDR_SHIFT 16 >>>> >>>> ++#define OUI_ADDR_MASK 0xFF >>>> >>>> ++ >>>> >>>> ++/* VLAN entry specifiers */ >>>> >>>> ++#define VLAN_INNER_ENTRY 0x0 >>>> >>>> ++#define VLAN_OUTER_ENTRY 0x2 >>>> >>>> ++#define VLAN_ETHERTYPE_ENTRY 0x4 >>>> >>>> ++#define VLAN_IPV4_ENTRY 0x6 >>>> >>>> ++#define VLAN_IPV6_ENTRY_MASK 0x1 >>>> >>>> ++ >>>> >>>> ++/* VLAN Inner/Outer table entry MASKs and SHIFTs*/ >>>> >>>> ++#define NOLEARN_FLAG_SHIFT 2 >>>> >>>> ++#define NOLEARN_FLAG_MASK 0x1FF >>>> >>>> ++#define INGRESS_CHECK_SHIFT 1 >>>> >>>> ++#define INGRESS_CHECK_MASK 0x1 >>>> >>>> ++#define VLAN_ID_SHIFT 16 >>>> >>>> ++#define VLAN_ID_MASK 0xFFF >>>> >>>> ++#define NOFRAG_FLAG_SHIFT_2G 12 >>>> >>>> ++#define NOFRAG_FLAG_MASK_2G 0x1 >>>> >>>> ++#define NOFRAG_FLAG_SHIFT 15 >>>> >>>> ++#define NOFRAG_FLAG_MASK 0x1 >>>> >>>> ++#define REG_MASK_SHIFT 4 >>>> >>>> ++#define REG_MASK_MASK 0x1FF >>>> >>>> ++#define PKT_EGRESS_W1_MASK 0x1 >>>> >>>> ++#define PKT_EGRESS_W1_OFFSET 512 >>>> >>>> ++#define PKT_EGRESS_SHIFT 24 >>>> >>>> ++#define PKT_EGRESS_MASK_2G 0x3 >>>> >>>> ++#define PKT_EGRESS_MASK 0x1FF >>>> >>>> ++#define UNREG_MASK_SHIFT_2G 20 >>>> >>>> ++#define UNREG_MASK_MASK_2G 0x7 >>>> >>>> ++#define UNREG_MASK_SHIFT 12 >>>> >>>> ++#define UNREG_MASK_MASK 0x1FF >>>> >>>> ++#define NXT_HDR_CTRL_SHIFT_2G 19 >>>> >>>> ++#define NXT_HDR_CTRL_MASK_2G 0x1 >>>> >>>> ++#define NXT_HDR_CTRL_SHIFT 23 >>>> >>>> ++#define NXT_HDR_CTRL_MASK 0x1 >>>> >>>> ++#define VLAN_MEMBER_LIST_MASK_2G 0x3 >>>> >>>> ++#define VLAN_MEMBER_LIST_MASK 0x1FF >>>> >>>> ++ >>>> >>>> ++/* VLAN IPv4 entry MASKs and SHIFTs*/ >>>> >>>> ++#define IPV4_ADDR_OCT1_SHIFT 24 >>>> >>>> ++#define IPV4_ADDR_OCT2_SHIFT 16 >>>> >>>> ++#define IPV4_ADDR_OCT3_SHIFT 8 >>>> >>>> ++#define IPV4_ADDR_MASK 0xFF >>>> >>>> ++ >>>> >>>> ++/* VLAN IPv6 entry MASKs and SHIFTs*/ >>>> >>>> ++#define IPV6_HIGH_ENTRY_FLAG 0x40 >>>> >>>> ++#define IPV6_IGNMCBITS_MASK 0xFF >>>> >>>> ++#define IPV6_HADDR_W1_SHIFT 12 >>>> >>>> ++#define IPV6_HADDR_W1_MASK_1 0xFFFF >>>> >>>> ++#define IPV6_HADDR_W1_MASK_2 0xFFF >>>> >>>> ++#define IPV6_HADDR_W0_SHIFT_1 28 >>>> >>>> ++#define IPV6_HADDR_W0_MASK_1 0xF >>>> >>>> ++#define IPV6_HADDR_W0_SHIFT_2 12 >>>> >>>> ++#define IPV6_HADDR_W0_MASK_2 0xFFFF >>>> >>>> ++#define IPV6_LADDR_W2_SHIFT 4 >>>> >>>> ++#define IPV6_LADDR_W2_MAKS 0xF >>>> >>>> ++#define IPV6_LADDR_W1_SHIFT 16 >>>> >>>> ++#define IPV6_LADDR_W1_MASK_1 0xFFF >>>> >>>> ++#define IPV6_LADDR_W1_MASK 0xFFFF >>>> >>>> ++#define IPV6_LADDR_W0_SHIFT 16 >>>> >>>> ++#define IPV6_LADDR_W0_MASK 0xFFFF >>>> >>>> ++ >>>> >>>> ++/** >>>> >>>> ++ * Since there are different instances of CPSW (namely cpsw2g, >>>> cpsw3g, cpsw5g and cpsw9g) >>>> >>>> ++ * some register offsets differ to get some parameters for ALE >>>> table, parse rtl_version >>>> >>>> ++ * from ALE_MOD_VER register to determine which instance is being >>>> used. >>>> >>>> ++ */ >>>> >>>> ++u32 rtl_version; >>>> >>>> ++ >>>> >>>> ++static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, >>>> u32 bits) >>>> >>>> ++{ >>>> >>>> ++ int idx; >>>> >>>> ++ >>>> >>>> ++ idx = start / ALE_WORD_LEN; >>>> >>>> ++ start -= idx * ALE_WORD_LEN; >>>> >>>> ++ >>>> >>>> ++ /** >>>> >>>> ++ * ALE words are stored in order word2, word1 and word0, flip >>>> the word to parse in numeric >>>> >>>> ++ * order >>>> >>>> ++ */ >>>> >>>> ++ idx = NUM_ALE_WORDS - idx; /* flip */ >>>> >>>> ++ return (ale_entry[idx] >> start) & BITMASK(bits); >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++#define DEFINE_ALE_FIELD(name, start, bits) \ >>>> >>>> ++static inline int cpsw_ale_get_##name(u32 *ale_entry) \ >>>> >>>> ++{ \ >>>> >>>> ++ return cpsw_ale_get_field(ale_entry, start, bits); \ >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++DEFINE_ALE_FIELD(entry_type, 60, 2) >>>> >>>> ++DEFINE_ALE_FIELD(vlan_id, 48, 12) >>>> >>>> ++DEFINE_ALE_FIELD(mcast_state, 62, 2) >>>> >>>> ++DEFINE_ALE_FIELD(port_mask, 66, 9) >>>> >>>> ++DEFINE_ALE_FIELD(super, 65, 1) >>>> >>>> ++DEFINE_ALE_FIELD(agable, 62, 1) >>>> >>>> ++DEFINE_ALE_FIELD(touched, 63, 1) >>>> >>>> ++DEFINE_ALE_FIELD(ucast_type, 62, 2) >>>> >>>> ++DEFINE_ALE_FIELD(port_num, 66, 4) >>>> >>>> ++DEFINE_ALE_FIELD(port_num_2g, 66, 1) >>>> >>>> ++DEFINE_ALE_FIELD(port_num_3g, 66, 2) >>>> >>>> ++DEFINE_ALE_FIELD(blocked, 65, 1) >>>> >>>> ++DEFINE_ALE_FIELD(secure, 64, 1) >>>> >>>> ++DEFINE_ALE_FIELD(oui_entry, 62, 2) >>>> >>>> ++DEFINE_ALE_FIELD(oui_addr, 4, 24) >>>> >>>> ++DEFINE_ALE_FIELD(mcast, 40, 1) >>>> >>>> ++DEFINE_ALE_FIELD(vlan_entry_type, 62, 3) >>>> >>>> ++DEFINE_ALE_FIELD(ethertype, 0, 16) >>>> >>>> ++DEFINE_ALE_FIELD(ipv4_addr, 0, 32) >>>> >>>> ++DEFINE_ALE_FIELD(ingress_bits, 65, 5) >>>> >>>> ++DEFINE_ALE_FIELD(ipv6_addr_low, 0, 60) >>>> >>>> ++DEFINE_ALE_FIELD(ipv6_addr_mid, 63, 8) >>>> >>>> ++DEFINE_ALE_FIELD(ipv6_addr_high, 0, 60) >>>> >>>> ++DEFINE_ALE_FIELD(entry_word0, 0, 32) >>>> >>>> ++DEFINE_ALE_FIELD(entry_word1, 32, 32) >>>> >>>> ++DEFINE_ALE_FIELD(entry_word2, 64, 12) >>>> >>>> ++ >>>> >>>> ++static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) >>>> >>>> ++{ >>>> >>>> ++ int i; >>>> >>>> ++ >>>> >>>> ++ for (i = 0; i < NUM_MAC_OCTET; i++) >>>> >>>> ++ addr[i] = cpsw_ale_get_field(ale_entry, MAC_START_BIT - >>>> MAC_OCTET_LEN * i, >>>> >>>> ++ MAC_OCTET_LEN); >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++struct k3_cpsw_regdump_hdr { >>>> >>>> ++ u32 module_id; >>>> >>>> ++ u32 len; >>>> >>>> ++}; >>>> >>>> ++ >>>> >>>> ++enum { >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_NUSS = 1, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_MDIO = 3, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_CPSW = 4, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_P0 = 5, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_PN = 6, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE = 8, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, >>>> >>>> ++ K3_CPSW_REGDUMP_MOD_LAST, >>>> >>>> ++}; >>>> >>>> ++ >>>> >>>> ++static const char *mod_names[K3_CPSW_REGDUMP_MOD_LAST] = { >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_NUSS] = "cpsw-nuss", >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_RGMII_STATUS] = "cpsw-nuss-rgmii-status", >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_MDIO] = "cpsw-nuss-mdio", >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW] = "cpsw-nu", >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_P0] = "cpsw-nu-p0", >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_PN] = "cpsw-nu-pn", >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_CPTS] = "cpsw-nu-cpts", >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE] = "cpsw-nu-ale", >>>> >>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL] = "cpsw-nu-ale-tbl", >>>> >>>> ++}; >>>> >>>> ++ >>>> >>>> ++static void cpsw_ale_dump_oui_entry(int index, u32 *ale_entry) >>>> >>>> ++{ >>>> >>>> ++ u32 oui_addr; >>>> >>>> ++ >>>> >>>> ++ oui_addr = cpsw_ale_get_oui_addr(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: OUI Unicast\n, \tOUI = >>>> %02x:%02x:%02x\n", >>>> >>>> ++ index, (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, >>>> >>>> ++ (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, oui_addr & >>>> OUI_ADDR_MASK); >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++static void cpsw_ale_dump_addr(int index, u32 *ale_entry) >>>> >>>> ++{ >>>> >>>> ++ u8 addr[NUM_MAC_OCTET]; >>>> >>>> ++ >>>> >>>> ++ cpsw_ale_get_addr(ale_entry, addr); >>>> >>>> ++ >>>> >>>> ++ if (cpsw_ale_get_mcast(ale_entry)) { >>>> >>>> ++ static const char * const str_mcast_state[] = {"Forwarding", >>>> >>>> ++ "Blocking/Forwarding/Learning", >>>> >>>> ++ "Learning/Forwarding", >>>> >>>> ++ "Forwarding"}; >>>> >>>> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >>>> >>>> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >>>> >>>> ++ u8 super = cpsw_ale_get_super(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: Multicast\n \tAddress = >>>> %02x:%02x:%02x:%02x:%02x:%02x, Multicast_State = %s, %sSuper, >>>> port_mask = 0x%x\n", >>>> >>>> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], >>>> addr[5], >>>> >>>> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >>>> >>>> ++ } else { >>>> >>>> ++ static const char * const s_ucast_type[] = {"Persistent", >>>> "Untouched", "OUI", >>>> >>>> ++ "Touched"}; >>>> >>>> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >>>> >>>> ++ u8 port_num = cpsw_ale_get_port_num(ale_entry); >>>> >>>> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >>>> >>>> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >>>> >>>> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >>>> >>>> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: Unicast\n \tUpdated Address = >>>> %02x:%02x:%02x:%02x:%02x:%02x, Unicast Type = %s, Port_num = 0x%x, >>>> Secure: %d, Blocked: %d, Touch = %d, Agable = %d\n", >>>> >>>> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], >>>> addr[5], >>>> >>>> ++ s_ucast_type[ucast_type], port_num, secure, blocked, >>>> touched, agable); >>>> >>>> ++ } >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++static void cpsw_ale_dump_inner_vlan_entry(int index, u32 *ale_entry) >>>> >>>> ++{ >>>> >>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>> >>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>> >>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: Inner VLAN\n \tNolearn Mask = 0x%x, >>>> Ingress Check = %d\n", >>>> >>>> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & >>>> NOLEARN_FLAG_MASK, >>>> >>>> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & >>>> INGRESS_CHECK_MASK); >>>> >>>> ++ >>>> >>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >>>> >>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered >>>> Mask = 0x%x\n", >>>> >>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>> >>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & >>>> NOFRAG_FLAG_MASK_2G, >>>> >>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>>> Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = >>>> 0x%x\n", >>>> >>>> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>>> PKT_EGRESS_MASK_2G, >>>> >>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & >>>> UNREG_MASK_MASK_2G, >>>> >>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & >>>> NXT_HDR_CTRL_MASK_2G, >>>> >>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >>>> >>>> ++ } else { >>>> >>>> ++ fprintf(stdout, "\tVLAN ID = %d, Registered Mask = 0x%x, >>>> No Frag = %d\n", >>>> >>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>> >>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK, >>>> >>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & >>>> NOFRAG_FLAG_MASK); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>>> Limit Next Header Control = %d, Unregistered Mask = 0x%x, Members = >>>> 0x%x\n", >>>> >>>> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * >>>> PKT_EGRESS_W1_OFFSET + >>>> >>>> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>>> PKT_EGRESS_MASK), >>>> >>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & >>>> NXT_HDR_CTRL_MASK, >>>> >>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, >>>> >>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >>>> >>>> ++ } >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++static void cpsw_ale_dump_outer_vlan_entry(int index, u32 *ale_entry) >>>> >>>> ++{ >>>> >>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>> >>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>> >>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: Outer VLAN\n \tNolearn Mask = 0x%x, >>>> Ingress Check = %d\n", >>>> >>>> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & >>>> NOLEARN_FLAG_MASK, >>>> >>>> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & >>>> INGRESS_CHECK_MASK); >>>> >>>> ++ >>>> >>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >>>> >>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered >>>> Mask = 0x%x\n", >>>> >>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>> >>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & >>>> NOFRAG_FLAG_MASK_2G, >>>> >>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>>> Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = >>>> 0x%x\n", >>>> >>>> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>>> PKT_EGRESS_MASK_2G, >>>> >>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & >>>> UNREG_MASK_MASK_2G, >>>> >>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & >>>> NXT_HDR_CTRL_MASK_2G, >>>> >>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >>>> >>>> ++ } else { >>>> >>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered >>>> Mask = 0x%x\n", >>>> >>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>> >>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & >>>> NOFRAG_FLAG_MASK, >>>> >>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>>> Limit Next Header Control = %d, Unregistered Mask = 0x%x Members = >>>> 0x%x\n", >>>> >>>> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * >>>> PKT_EGRESS_W1_OFFSET + >>>> >>>> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>>> PKT_EGRESS_MASK), >>>> >>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & >>>> NXT_HDR_CTRL_MASK, >>>> >>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, >>>> >>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >>>> >>>> ++ } >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++static void cpsw_ale_dump_ethertype_entry(int index, u32 *ale_entry) >>>> >>>> ++{ >>>> >>>> ++ u16 ethertype = cpsw_ale_get_ethertype(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: VLAN Ethertype\n \tEthertype = >>>> 0x%x\n", index, ethertype); >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++static void cpsw_ale_dump_ipv4_entry(int index, u32 *ale_entry) >>>> >>>> ++{ >>>> >>>> ++ u8 ingress_bits = cpsw_ale_get_ingress_bits(ale_entry); >>>> >>>> ++ u32 ipv4_addr = cpsw_ale_get_ipv4_addr(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: VLAN IPv4\n \tIngress Bits: 0x%x >>>> IPv4 Address = %u.%u.%u.%u\n", >>>> >>>> ++ index, ingress_bits, ipv4_addr >> IPV4_ADDR_OCT1_SHIFT & >>>> IPV4_ADDR_MASK, >>>> >>>> ++ ipv4_addr >> IPV4_ADDR_OCT2_SHIFT & IPV4_ADDR_MASK, >>>> >>>> ++ ipv4_addr >> IPV4_ADDR_OCT3_SHIFT & IPV4_ADDR_MASK, >>>> ipv4_addr & IPV4_ADDR_MASK); >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++static void cpsw_ale_dump_ipv6_entry(int index, u32 *ale_entry) >>>> >>>> ++{ >>>> >>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>> >>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>> >>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>> >>>> ++ >>>> >>>> ++ if (index & IPV6_HIGH_ENTRY_FLAG) { >>>> >>>> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Higher Entry (Lower >>>> Bit entry at %04u)\n \tIgnored Multicast bits: 0x%x, IPv6 Address >>>> (Bits [127:68]) = %04x:%03x%01x:%04x:%03x\n", >>>> >>>> ++ index, (index & (~IPV6_HIGH_ENTRY_FLAG)), >>>> >>>> ++ vlan_entry_word2 & IPV6_IGNMCBITS_MASK, >>>> >>>> ++ (vlan_entry_word1 >> IPV6_HADDR_W1_SHIFT) & >>>> IPV6_HADDR_W1_MASK_1, >>>> >>>> ++ vlan_entry_word1 & IPV6_HADDR_W1_MASK_2, >>>> >>>> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_1) & >>>> IPV6_HADDR_W0_MASK_1, >>>> >>>> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_2) & >>>> IPV6_HADDR_W0_MASK_2, >>>> >>>> ++ vlan_entry_word0 & IPV6_HADDR_W0_MASK_2); >>>> >>>> ++ } else { >>>> >>>> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Lower Entry (Higher >>>> Bit entry at %04u)\n \tIPv6 Address (Bits [127:68]) = >>>> %01x:%01x%03x:%04x:%04x:%04x\n", >>>> >>>> ++ index, (index | IPV6_HIGH_ENTRY_FLAG), >>>> >>>> ++ (vlan_entry_word2 >> IPV6_LADDR_W2_SHIFT) & >>>> IPV6_LADDR_W2_MAKS, >>>> >>>> ++ vlan_entry_word2 & IPV6_LADDR_W2_MAKS, >>>> >>>> ++ (vlan_entry_word1 >> IPV6_LADDR_W1_SHIFT) & >>>> IPV6_LADDR_W1_MASK_1, >>>> >>>> ++ vlan_entry_word1 & IPV6_LADDR_W1_MASK, >>>> >>>> ++ (vlan_entry_word0 >> IPV6_LADDR_W0_SHIFT) & >>>> IPV6_LADDR_W0_MASK, >>>> >>>> ++ vlan_entry_word0 & IPV6_LADDR_W0_MASK); >>>> >>>> ++ } >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry) >>>> >>>> ++{ >>>> >>>> ++ u8 addr[NUM_MAC_OCTET]; >>>> >>>> ++ int vlan = cpsw_ale_get_vlan_id(ale_entry); >>>> >>>> ++ >>>> >>>> ++ cpsw_ale_get_addr(ale_entry, addr); >>>> >>>> ++ if (cpsw_ale_get_mcast(ale_entry)) { >>>> >>>> ++ static const char * const str_mcast_state[] = {"Forwarding", >>>> >>>> ++ "Blocking/Forwarding/Learning", >>>> >>>> ++ "Learning/Forwarding", >>>> >>>> ++ "Forwarding"}; >>>> >>>> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >>>> >>>> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >>>> >>>> ++ u8 super = cpsw_ale_get_super(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: Multicast\n \tVID = %d, Address >>>> = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_state = %s, %s Super, >>>> port_mask = 0x%x\n", >>>> >>>> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], >>>> addr[4], addr[5], >>>> >>>> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >>>> >>>> ++ } else { >>>> >>>> ++ static const char * const s_ucast_type[] = {"Persistent", >>>> "Untouched", "OUI", >>>> >>>> ++ "Touched"}; >>>> >>>> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >>>> >>>> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >>>> >>>> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >>>> >>>> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >>>> >>>> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >>>> >>>> ++ >>>> >>>> ++ int port_num; >>>> >>>> ++ >>>> >>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) >>>> >>>> ++ port_num = cpsw_ale_get_port_num_2g(ale_entry); >>>> >>>> ++ else if (rtl_version == CPSW3G_RTL_VERSION) >>>> >>>> ++ port_num = cpsw_ale_get_port_num_3g(ale_entry); >>>> >>>> ++ else >>>> >>>> ++ port_num = cpsw_ale_get_port_num(ale_entry); >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%d: Type: Unicast\n \tVID = %d, Address = >>>> %02x:%02x:%02x:%02x:%02x:%02x, Unicast_type = %s, port_num = 0x%x, >>>> Secure = %d, Blocked = %d, Touch = %d, Agable = %d\n", >>>> >>>> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], >>>> addr[4], addr[5], >>>> >>>> ++ s_ucast_type[ucast_type], port_num, secure, blocked, >>>> touched, agable); >>>> >>>> ++ } >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++void cpsw_dump_ale(struct k3_cpsw_regdump_hdr *ale_hdr, u32 *ale_pos) >>>> >>>> ++{ >>>> >>>> ++ int i, ale_entries; >>>> >>>> ++ >>>> >>>> ++ if (!ale_hdr) >>>> >>>> ++ return; >>>> >>>> ++ >>>> >>>> ++ ale_entries = (ale_hdr->len - sizeof(struct >>>> k3_cpsw_regdump_hdr)) / >>>> >>>> ++ ALE_ENTRY_WORDS / sizeof(u32); >>>> >>>> ++ >>>> >>>> ++ printf("Number of ALE entries: %d\n", ale_entries); >>>> >>>> ++ ale_pos += 2; >>>> >>>> ++ for (i = 0; i < ale_entries; i++) { >>>> >>>> ++ int type; >>>> >>>> ++ >>>> >>>> ++ type = cpsw_ale_get_entry_type(ale_pos); >>>> >>>> ++ >>>> >>>> ++ switch (type) { >>>> >>>> ++ case ALE_ENTRY_FREE: >>>> >>>> ++ break; >>>> >>>> ++ >>>> >>>> ++ case ALE_ENTRY_ADDR: >>>> >>>> ++ u32 oui_entry = cpsw_ale_get_oui_addr(ale_pos); >>>> >>>> ++ >>>> >>>> ++ if (oui_entry == 0x2) >>>> >>>> ++ cpsw_ale_dump_oui_entry(i, ale_pos); >>>> >>>> ++ else >>>> >>>> ++ cpsw_ale_dump_addr(i, ale_pos); >>>> >>>> ++ break; >>>> >>>> ++ >>>> >>>> ++ case ALE_ENTRY_VLAN: >>>> >>>> ++ u32 vlan_entry_type = >>>> cpsw_ale_get_vlan_entry_type(ale_pos); >>>> >>>> ++ >>>> >>>> ++ if (vlan_entry_type == VLAN_INNER_ENTRY) >>>> >>>> ++ cpsw_ale_dump_inner_vlan_entry(i, ale_pos); >>>> >>>> ++ else if (vlan_entry_type == VLAN_OUTER_ENTRY) >>>> >>>> ++ cpsw_ale_dump_outer_vlan_entry(i, ale_pos); >>>> >>>> ++ else if (vlan_entry_type == VLAN_ETHERTYPE_ENTRY) >>>> >>>> ++ cpsw_ale_dump_ethertype_entry(i, ale_pos); >>>> >>>> ++ else if (vlan_entry_type == VLAN_IPV4_ENTRY) >>>> >>>> ++ cpsw_ale_dump_ipv4_entry(i, ale_pos); >>>> >>>> ++ else if (vlan_entry_type & VLAN_IPV6_ENTRY_MASK) >>>> >>>> ++ cpsw_ale_dump_ipv6_entry(i, ale_pos); >>>> >>>> ++ break; >>>> >>>> ++ >>>> >>>> ++ case ALE_ENTRY_VLAN_ADDR: >>>> >>>> ++ cpsw_ale_dump_vlan_addr(i, ale_pos); >>>> >>>> ++ break; >>>> >>>> ++ >>>> >>>> ++ default: >>>> >>>> ++ break; >>>> >>>> ++ } >>>> >>>> ++ >>>> >>>> ++ ale_pos += ALE_ENTRY_WORDS; >>>> >>>> ++ } >>>> >>>> ++} >>>> >>>> ++ >>>> >>>> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused, >>>> >>>> ++ struct ethtool_regs *regs) >>>> >>>> ++{ >>>> >>>> ++ struct k3_cpsw_regdump_hdr *dump_hdr, *ale_hdr = NULL; >>>> >>>> ++ u32 *reg = (u32 *)regs->data, *ale_pos; >>>> >>>> ++ u32 mod_id; >>>> >>>> ++ int i, regdump_len = info->regdump_len; >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "K3 CPSW dump version: %d, len: %d\n", >>>> >>>> ++ regs->version, info->regdump_len); >>>> >>>> ++ fprintf(stdout, "(Missing registers in memory space can be >>>> considered as zero valued)\n"); >>>> >>>> ++ >>>> >>>> ++ /* Line break before register dump */ >>>> >>>> ++ fprintf(stdout, >>>> "--------------------------------------------------------------------\n"); >>>> >>>> ++ i = 0; >>>> >>>> ++ do { >>>> >>>> ++ u32 *tmp, j; >>>> >>>> ++ u32 num_items; >>>> >>>> ++ >>>> >>>> ++ dump_hdr = (struct k3_cpsw_regdump_hdr *)reg; >>>> >>>> ++ mod_id = dump_hdr->module_id; >>>> >>>> ++ >>>> >>>> ++ num_items = dump_hdr->len / sizeof(u32); >>>> >>>> ++ >>>> >>>> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE) >>>> >>>> ++ rtl_version = reg[3] & RTL_VERSION_MASK; >>>> >>>> ++ >>>> >>>> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { >>>> >>>> ++ ale_hdr = dump_hdr; >>>> >>>> ++ ale_pos = reg; >>>> >>>> ++ break; >>>> >>>> ++ } >>>> >>>> ++ >>>> >>>> ++ fprintf(stdout, "%s regdump: number of Registers:(%d)\n", >>>> >>>> ++ mod_names[mod_id], num_items - 2); >>>> >>>> ++ tmp = reg; >>>> >>>> ++ /* Values are stored in pair as reg_offset-reg_val, hence >>>> parse the same way*/ >>>> >>>> ++ for (j = 2; j < num_items; j += 2) { >>>> >>>> ++ if (tmp[j + 1] != 0x0) >>>> >>>> ++ fprintf(stdout, "%08x:reg(%08X)\n", tmp[j], tmp[j >>>> + 1]); >>>> >>>> ++ } >>>> >>>> ++ >>>> >>>> ++ reg += num_items; >>>> >>>> ++ i += dump_hdr->len; >>>> >>>> ++ } while (i < regdump_len); >>>> >>>> ++ >>>> >>>> ++ /* Adding a boundary in between Register dump and ALE table */ >>>> >>>> ++ fprintf(stdout, "--------------------------\n"); >>>> >>>> ++ >>>> >>>> ++ cpsw_dump_ale(ale_hdr, ale_pos); >>>> >>>> ++ >>>> >>>> ++ return 0; >>>> >>>> ++}; >>>> >>>> +diff --git a/ethtool.c b/ethtool.c >>>> >>>> +index 3ac15a7..a383eb6 100644 >>>> >>>> +--- a/ethtool.c >>>> >>>> ++++ b/ethtool.c >>>> >>>> +@@ -1162,6 +1162,7 @@ static const struct { >>>> >>>> + { "fsl_enetc", fsl_enetc_dump_regs }, >>>> >>>> + { "fsl_enetc_vf", fsl_enetc_dump_regs }, >>>> >>>> + { "hns3", hns3_dump_regs }, >>>> >>>> ++ { "am65-cpsw-nuss", am65_cpsw_dump_regs }, >>>> >>>> + }; >>>> >>>> + #endif >>>> >>>> + >>>> >>>> +diff --git a/internal.h b/internal.h >>>> >>>> +index 4b994f5..81212b4 100644 >>>> >>>> +--- a/internal.h >>>> >>>> ++++ b/internal.h >>>> >>>> +@@ -410,4 +410,7 @@ int cpsw_dump_regs(struct ethtool_drvinfo >>>> *info, struct ethtool_regs *regs); >>>> >>>> + /* Microchip Ethernet Controller */ >>>> >>>> + int lan743x_dump_regs(struct ethtool_drvinfo *info, struct >>>> ethtool_regs *regs); >>>> >>>> + >>>> >>>> ++/* TI K3 CPSW Ethernet Switch */ >>>> >>>> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info, struct >>>> ethtool_regs *regs); >>>> >>>> ++ >>>> >>>> + #endif /* ETHTOOL_INTERNAL_H__ */ >>>> >>>> +-- >>>> >>>> +2.34.1 >>>> >>>> + >>>> >>>> diff --git >>>> a/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>> b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>> new file mode 100644 >>>> index 00000000..3b388151 >>>> --- /dev/null >>>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>> @@ -0,0 +1,4 @@ >>>> +ETHTOOL_ARAGO = "" >>>> +ETHTOOL_ARAGO:arago = "ethtool-arago.inc" >>>> + >>>> +require ${ETHTOOL_ARAGO} >>>> -- >>>> 2.34.1 >> >> >> -=-=-=-=-=-=-=-=-=-=-=- >> Links: You receive all messages sent to this group. >> View/Reply Online (#16281): >> https://lists.yoctoproject.org/g/meta-arago/message/16281 >> Mute This Topic: https://lists.yoctoproject.org/mt/114024756/6607860 >> Group Owner: meta-arago+owner@lists.yoctoproject.org >> Unsubscribe: https://lists.yoctoproject.org/g/meta-arago/unsub >> [a-limaye@ti.com] >> -=-=-=-=-=-=-=-=-=-=-=- >> >> -- Ryan Eatmon reatmon@ti.com ----------------------------------------- Texas Instruments, Inc. - LCPD - MGTS
On 7/11/25 12:31 PM, Ryan Eatmon via lists.yoctoproject.org wrote: > > > On 7/10/2025 9:35 PM, Aniket Limaye wrote: >> Denys, Ryan, >> >> On 11/07/25 07:04, Aniket Limaye via lists.yoctoproject.org wrote: >>> >>> >>> On 11/07/25 06:02, Denys Dmytriyenko wrote: >>>> I wonder if the patch itself is malformed - specifically if it has windows >>>> newlines that result in interlaced empty lines in mutt on Linux, as seen >>>> below. While .inc and .bbappend seem fine. >>>> >>> >>> Chintan, Yeah looks like the patchfile I added was not properly formatted. I will try resending this one quickly. >>> >> >> Not sure what caused the weird encoding in the first place... >> >> Sent v2 here: https://lists.yoctoproject.org/g/meta-arago/message/16282 > > What's really odd is that applying the v1 patch resulted in a perfectly fine file in the repo. I applied this patch yesterday and the patch file looks fine. Or am I wrong. The issue is that this patch is already on next and is going through CICD promotion right now. If this is a problem we may need to submit a follow on patch to fix it. Can someone check the current file in the repo and verify? > > $ git checkout 83558083 $ file meta-arago-distro/recipes-extended/ethtool/ethtool/0001-pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch meta-arago-distro/recipes-extended/ethtool/ethtool/0001-pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch: unified diff output, ASCII text Looks fine to me, all those odd newlines must have been removed by whatever tool you used to apply the email. Andrew > >> >>> Thanks, >>> Aniket >>> >>>> >>>> On Mon, Jul 07, 2025 at 02:37:20PM +0530, Aniket Limaye via lists.yoctoproject.org wrote: >>>>> Add support for TI K3 CPSW register and ALE table dump through the >>>>> ethtool userspace utility. >>>>> >>>>> Signed-off-by: Aniket Limaye <a-limaye@ti.com> >>>>> --- >>>>> .../ethtool/ethtool-arago.inc | 8 + >>>>> ...k3-cpsw-registers-and-ale-table-dump.patch | 574 ++++++++++++++++++ >>>>> .../ethtool/ethtool_%.bbappend | 4 + >>>>> 3 files changed, 586 insertions(+) >>>>> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>>> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>>> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>>> >>>>> diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>>> new file mode 100644 >>>>> index 00000000..5fd05a85 >>>>> --- /dev/null >>>>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>>> @@ -0,0 +1,8 @@ >>>>> +PR:append = ".arago0" >>>>> + >>>>> +FILESEXTRAPATHS:prepend := "${THISDIR}/ethtool:" >>>>> + >>>>> +SRC_URI:append = " \ >>>>> + file://pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch \ >>>>> + " >>>>> + >>>>> diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>>> new file mode 100644 >>>>> index 00000000..a14089b4 >>>>> --- /dev/null >>>>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>>> @@ -0,0 +1,574 @@ >>>>> +From: Chintan Vankar <c-vankar@ti.com> >>>>> >>>>> +Subject: [PATCH] pretty: Add support for TI K3 CPSW registers and ALE table dump >>>>> >>>>> +Date: Thu, 3 Jul 2025 12:02:46 +0530 >>>>> >>>>> + >>>>> >>>>> +Add support to dump CPSW registers and ALE table for the CPSW instances on >>>>> >>>>> +K3 SoCs that are configured using the am65-cpsw-nuss.c device-driver in >>>>> >>>>> +Linux. >>>>> >>>>> + >>>>> >>>>> +Upstream-Status: Submitted [https://lore.kernel.org/all/20250705134807.3514891-1-c-vankar@ti.com/] >>>>> >>>>> +Signed-off-by: Chintan Vankar <c-vankar@ti.com> >>>>> >>>>> +--- >>>>> >>>>> + Makefile.am | 2 +- >>>>> >>>>> + am65-cpsw-nuss.c | 510 +++++++++++++++++++++++++++++++++++++++++++++++ >>>>> >>>>> + ethtool.c | 1 + >>>>> >>>>> + internal.h | 3 + >>>>> >>>>> + 4 files changed, 515 insertions(+), 1 deletion(-) >>>>> >>>>> + create mode 100644 am65-cpsw-nuss.c >>>>> >>>>> + >>>>> >>>>> +diff --git a/Makefile.am b/Makefile.am >>>>> >>>>> +index b9e06ad..fe6afcb 100644 >>>>> >>>>> +--- a/Makefile.am >>>>> >>>>> ++++ b/Makefile.am >>>>> >>>>> +@@ -23,7 +23,7 @@ ethtool_SOURCES += \ >>>>> >>>>> + smsc911x.c at76c50x-usb.c sfc.c stmmac.c \ >>>>> >>>>> + sff-common.c sff-common.h sfpid.c sfpdiag.c \ >>>>> >>>>> + ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c \ >>>>> >>>>> +- igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c >>>>> >>>>> ++ igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c am65-cpsw-nuss.c >>>>> >>>>> + endif >>>>> >>>>> + >>>>> >>>>> + if ENABLE_BASH_COMPLETION >>>>> >>>>> +diff --git a/am65-cpsw-nuss.c b/am65-cpsw-nuss.c >>>>> >>>>> +new file mode 100644 >>>>> >>>>> +index 0000000..de8e3e9 >>>>> >>>>> +--- /dev/null >>>>> >>>>> ++++ b/am65-cpsw-nuss.c >>>>> >>>>> +@@ -0,0 +1,510 @@ >>>>> >>>>> ++// SPDX-License-Identifier: GPL-2.0-only OR MIT >>>>> >>>>> ++/* Code to dump registers and ALE table for the CPSW instances on K3 SoCs that are configured using >>>>> >>>>> ++ * the am65-cpsw-nuss device-driver in Linux. >>>>> >>>>> ++ * >>>>> >>>>> ++ * Copyright (C) 2025 Texas Instruments >>>>> >>>>> ++ * Author: Chintan Vankar <c-vankar@ti.com> >>>>> >>>>> ++ */ >>>>> >>>>> ++ >>>>> >>>>> ++#include <stdio.h> >>>>> >>>>> ++#include <string.h> >>>>> >>>>> ++ >>>>> >>>>> ++#include "internal.h" >>>>> >>>>> ++ >>>>> >>>>> ++#define ALE_ENTRY_BITS 74 >>>>> >>>>> ++#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) >>>>> >>>>> ++ >>>>> >>>>> ++#define ALE_ENTRY_FREE 0x0 >>>>> >>>>> ++#define ALE_ENTRY_ADDR 0x1 >>>>> >>>>> ++#define ALE_ENTRY_VLAN 0x2 >>>>> >>>>> ++#define ALE_ENTRY_VLAN_ADDR 0x3 >>>>> >>>>> ++ >>>>> >>>>> ++#define BIT(nr) (1 << (nr)) >>>>> >>>>> ++#define BITMASK(bits) (BIT(bits) - 1) >>>>> >>>>> ++ >>>>> >>>>> ++/* ALE word specifiers */ >>>>> >>>>> ++#define NUM_ALE_WORDS 2 >>>>> >>>>> ++#define ALE_WORD_LEN 32 >>>>> >>>>> ++ >>>>> >>>>> ++/* MAC address specifiers */ >>>>> >>>>> ++#define MAC_START_BIT 40 >>>>> >>>>> ++#define MAC_OCTET_LEN 8 >>>>> >>>>> ++#define NUM_MAC_OCTET 6 >>>>> >>>>> ++ >>>>> >>>>> ++/* RTL version specifiers */ >>>>> >>>>> ++#define RTL_VERSION_MASK 0xF800 >>>>> >>>>> ++#define CPSW2G_RTL_VERSION 0x3800 >>>>> >>>>> ++#define CPSW3G_RTL_VERSION 0x0 >>>>> >>>>> ++ >>>>> >>>>> ++/* OUI address uses format xx:xx:xx, use OUI shift as 16 bits and MASK as 0xFF to parse the same*/ >>>>> >>>>> ++#define OUI_ADDR_SHIFT 16 >>>>> >>>>> ++#define OUI_ADDR_MASK 0xFF >>>>> >>>>> ++ >>>>> >>>>> ++/* VLAN entry specifiers */ >>>>> >>>>> ++#define VLAN_INNER_ENTRY 0x0 >>>>> >>>>> ++#define VLAN_OUTER_ENTRY 0x2 >>>>> >>>>> ++#define VLAN_ETHERTYPE_ENTRY 0x4 >>>>> >>>>> ++#define VLAN_IPV4_ENTRY 0x6 >>>>> >>>>> ++#define VLAN_IPV6_ENTRY_MASK 0x1 >>>>> >>>>> ++ >>>>> >>>>> ++/* VLAN Inner/Outer table entry MASKs and SHIFTs*/ >>>>> >>>>> ++#define NOLEARN_FLAG_SHIFT 2 >>>>> >>>>> ++#define NOLEARN_FLAG_MASK 0x1FF >>>>> >>>>> ++#define INGRESS_CHECK_SHIFT 1 >>>>> >>>>> ++#define INGRESS_CHECK_MASK 0x1 >>>>> >>>>> ++#define VLAN_ID_SHIFT 16 >>>>> >>>>> ++#define VLAN_ID_MASK 0xFFF >>>>> >>>>> ++#define NOFRAG_FLAG_SHIFT_2G 12 >>>>> >>>>> ++#define NOFRAG_FLAG_MASK_2G 0x1 >>>>> >>>>> ++#define NOFRAG_FLAG_SHIFT 15 >>>>> >>>>> ++#define NOFRAG_FLAG_MASK 0x1 >>>>> >>>>> ++#define REG_MASK_SHIFT 4 >>>>> >>>>> ++#define REG_MASK_MASK 0x1FF >>>>> >>>>> ++#define PKT_EGRESS_W1_MASK 0x1 >>>>> >>>>> ++#define PKT_EGRESS_W1_OFFSET 512 >>>>> >>>>> ++#define PKT_EGRESS_SHIFT 24 >>>>> >>>>> ++#define PKT_EGRESS_MASK_2G 0x3 >>>>> >>>>> ++#define PKT_EGRESS_MASK 0x1FF >>>>> >>>>> ++#define UNREG_MASK_SHIFT_2G 20 >>>>> >>>>> ++#define UNREG_MASK_MASK_2G 0x7 >>>>> >>>>> ++#define UNREG_MASK_SHIFT 12 >>>>> >>>>> ++#define UNREG_MASK_MASK 0x1FF >>>>> >>>>> ++#define NXT_HDR_CTRL_SHIFT_2G 19 >>>>> >>>>> ++#define NXT_HDR_CTRL_MASK_2G 0x1 >>>>> >>>>> ++#define NXT_HDR_CTRL_SHIFT 23 >>>>> >>>>> ++#define NXT_HDR_CTRL_MASK 0x1 >>>>> >>>>> ++#define VLAN_MEMBER_LIST_MASK_2G 0x3 >>>>> >>>>> ++#define VLAN_MEMBER_LIST_MASK 0x1FF >>>>> >>>>> ++ >>>>> >>>>> ++/* VLAN IPv4 entry MASKs and SHIFTs*/ >>>>> >>>>> ++#define IPV4_ADDR_OCT1_SHIFT 24 >>>>> >>>>> ++#define IPV4_ADDR_OCT2_SHIFT 16 >>>>> >>>>> ++#define IPV4_ADDR_OCT3_SHIFT 8 >>>>> >>>>> ++#define IPV4_ADDR_MASK 0xFF >>>>> >>>>> ++ >>>>> >>>>> ++/* VLAN IPv6 entry MASKs and SHIFTs*/ >>>>> >>>>> ++#define IPV6_HIGH_ENTRY_FLAG 0x40 >>>>> >>>>> ++#define IPV6_IGNMCBITS_MASK 0xFF >>>>> >>>>> ++#define IPV6_HADDR_W1_SHIFT 12 >>>>> >>>>> ++#define IPV6_HADDR_W1_MASK_1 0xFFFF >>>>> >>>>> ++#define IPV6_HADDR_W1_MASK_2 0xFFF >>>>> >>>>> ++#define IPV6_HADDR_W0_SHIFT_1 28 >>>>> >>>>> ++#define IPV6_HADDR_W0_MASK_1 0xF >>>>> >>>>> ++#define IPV6_HADDR_W0_SHIFT_2 12 >>>>> >>>>> ++#define IPV6_HADDR_W0_MASK_2 0xFFFF >>>>> >>>>> ++#define IPV6_LADDR_W2_SHIFT 4 >>>>> >>>>> ++#define IPV6_LADDR_W2_MAKS 0xF >>>>> >>>>> ++#define IPV6_LADDR_W1_SHIFT 16 >>>>> >>>>> ++#define IPV6_LADDR_W1_MASK_1 0xFFF >>>>> >>>>> ++#define IPV6_LADDR_W1_MASK 0xFFFF >>>>> >>>>> ++#define IPV6_LADDR_W0_SHIFT 16 >>>>> >>>>> ++#define IPV6_LADDR_W0_MASK 0xFFFF >>>>> >>>>> ++ >>>>> >>>>> ++/** >>>>> >>>>> ++ * Since there are different instances of CPSW (namely cpsw2g, cpsw3g, cpsw5g and cpsw9g) >>>>> >>>>> ++ * some register offsets differ to get some parameters for ALE table, parse rtl_version >>>>> >>>>> ++ * from ALE_MOD_VER register to determine which instance is being used. >>>>> >>>>> ++ */ >>>>> >>>>> ++u32 rtl_version; >>>>> >>>>> ++ >>>>> >>>>> ++static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) >>>>> >>>>> ++{ >>>>> >>>>> ++ int idx; >>>>> >>>>> ++ >>>>> >>>>> ++ idx = start / ALE_WORD_LEN; >>>>> >>>>> ++ start -= idx * ALE_WORD_LEN; >>>>> >>>>> ++ >>>>> >>>>> ++ /** >>>>> >>>>> ++ * ALE words are stored in order word2, word1 and word0, flip the word to parse in numeric >>>>> >>>>> ++ * order >>>>> >>>>> ++ */ >>>>> >>>>> ++ idx = NUM_ALE_WORDS - idx; /* flip */ >>>>> >>>>> ++ return (ale_entry[idx] >> start) & BITMASK(bits); >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++#define DEFINE_ALE_FIELD(name, start, bits) \ >>>>> >>>>> ++static inline int cpsw_ale_get_##name(u32 *ale_entry) \ >>>>> >>>>> ++{ \ >>>>> >>>>> ++ return cpsw_ale_get_field(ale_entry, start, bits); \ >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++DEFINE_ALE_FIELD(entry_type, 60, 2) >>>>> >>>>> ++DEFINE_ALE_FIELD(vlan_id, 48, 12) >>>>> >>>>> ++DEFINE_ALE_FIELD(mcast_state, 62, 2) >>>>> >>>>> ++DEFINE_ALE_FIELD(port_mask, 66, 9) >>>>> >>>>> ++DEFINE_ALE_FIELD(super, 65, 1) >>>>> >>>>> ++DEFINE_ALE_FIELD(agable, 62, 1) >>>>> >>>>> ++DEFINE_ALE_FIELD(touched, 63, 1) >>>>> >>>>> ++DEFINE_ALE_FIELD(ucast_type, 62, 2) >>>>> >>>>> ++DEFINE_ALE_FIELD(port_num, 66, 4) >>>>> >>>>> ++DEFINE_ALE_FIELD(port_num_2g, 66, 1) >>>>> >>>>> ++DEFINE_ALE_FIELD(port_num_3g, 66, 2) >>>>> >>>>> ++DEFINE_ALE_FIELD(blocked, 65, 1) >>>>> >>>>> ++DEFINE_ALE_FIELD(secure, 64, 1) >>>>> >>>>> ++DEFINE_ALE_FIELD(oui_entry, 62, 2) >>>>> >>>>> ++DEFINE_ALE_FIELD(oui_addr, 4, 24) >>>>> >>>>> ++DEFINE_ALE_FIELD(mcast, 40, 1) >>>>> >>>>> ++DEFINE_ALE_FIELD(vlan_entry_type, 62, 3) >>>>> >>>>> ++DEFINE_ALE_FIELD(ethertype, 0, 16) >>>>> >>>>> ++DEFINE_ALE_FIELD(ipv4_addr, 0, 32) >>>>> >>>>> ++DEFINE_ALE_FIELD(ingress_bits, 65, 5) >>>>> >>>>> ++DEFINE_ALE_FIELD(ipv6_addr_low, 0, 60) >>>>> >>>>> ++DEFINE_ALE_FIELD(ipv6_addr_mid, 63, 8) >>>>> >>>>> ++DEFINE_ALE_FIELD(ipv6_addr_high, 0, 60) >>>>> >>>>> ++DEFINE_ALE_FIELD(entry_word0, 0, 32) >>>>> >>>>> ++DEFINE_ALE_FIELD(entry_word1, 32, 32) >>>>> >>>>> ++DEFINE_ALE_FIELD(entry_word2, 64, 12) >>>>> >>>>> ++ >>>>> >>>>> ++static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) >>>>> >>>>> ++{ >>>>> >>>>> ++ int i; >>>>> >>>>> ++ >>>>> >>>>> ++ for (i = 0; i < NUM_MAC_OCTET; i++) >>>>> >>>>> ++ addr[i] = cpsw_ale_get_field(ale_entry, MAC_START_BIT - MAC_OCTET_LEN * i, >>>>> >>>>> ++ MAC_OCTET_LEN); >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++struct k3_cpsw_regdump_hdr { >>>>> >>>>> ++ u32 module_id; >>>>> >>>>> ++ u32 len; >>>>> >>>>> ++}; >>>>> >>>>> ++ >>>>> >>>>> ++enum { >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_NUSS = 1, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_MDIO = 3, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW = 4, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_P0 = 5, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_PN = 6, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE = 8, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, >>>>> >>>>> ++ K3_CPSW_REGDUMP_MOD_LAST, >>>>> >>>>> ++}; >>>>> >>>>> ++ >>>>> >>>>> ++static const char *mod_names[K3_CPSW_REGDUMP_MOD_LAST] = { >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_NUSS] = "cpsw-nuss", >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_RGMII_STATUS] = "cpsw-nuss-rgmii-status", >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_MDIO] = "cpsw-nuss-mdio", >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW] = "cpsw-nu", >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_P0] = "cpsw-nu-p0", >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_PN] = "cpsw-nu-pn", >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_CPTS] = "cpsw-nu-cpts", >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE] = "cpsw-nu-ale", >>>>> >>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL] = "cpsw-nu-ale-tbl", >>>>> >>>>> ++}; >>>>> >>>>> ++ >>>>> >>>>> ++static void cpsw_ale_dump_oui_entry(int index, u32 *ale_entry) >>>>> >>>>> ++{ >>>>> >>>>> ++ u32 oui_addr; >>>>> >>>>> ++ >>>>> >>>>> ++ oui_addr = cpsw_ale_get_oui_addr(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: OUI Unicast\n, \tOUI = %02x:%02x:%02x\n", >>>>> >>>>> ++ index, (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, >>>>> >>>>> ++ (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, oui_addr & OUI_ADDR_MASK); >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++static void cpsw_ale_dump_addr(int index, u32 *ale_entry) >>>>> >>>>> ++{ >>>>> >>>>> ++ u8 addr[NUM_MAC_OCTET]; >>>>> >>>>> ++ >>>>> >>>>> ++ cpsw_ale_get_addr(ale_entry, addr); >>>>> >>>>> ++ >>>>> >>>>> ++ if (cpsw_ale_get_mcast(ale_entry)) { >>>>> >>>>> ++ static const char * const str_mcast_state[] = {"Forwarding", >>>>> >>>>> ++ "Blocking/Forwarding/Learning", >>>>> >>>>> ++ "Learning/Forwarding", >>>>> >>>>> ++ "Forwarding"}; >>>>> >>>>> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >>>>> >>>>> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >>>>> >>>>> ++ u8 super = cpsw_ale_get_super(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: Multicast\n \tAddress = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_State = %s, %sSuper, port_mask = 0x%x\n", >>>>> >>>>> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], >>>>> >>>>> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >>>>> >>>>> ++ } else { >>>>> >>>>> ++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", >>>>> >>>>> ++ "Touched"}; >>>>> >>>>> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >>>>> >>>>> ++ u8 port_num = cpsw_ale_get_port_num(ale_entry); >>>>> >>>>> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >>>>> >>>>> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >>>>> >>>>> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >>>>> >>>>> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: Unicast\n \tUpdated Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast Type = %s, Port_num = 0x%x, Secure: %d, Blocked: %d, Touch = %d, Agable = %d\n", >>>>> >>>>> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], >>>>> >>>>> ++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); >>>>> >>>>> ++ } >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++static void cpsw_ale_dump_inner_vlan_entry(int index, u32 *ale_entry) >>>>> >>>>> ++{ >>>>> >>>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>>> >>>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>>> >>>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: Inner VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", >>>>> >>>>> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, >>>>> >>>>> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); >>>>> >>>>> ++ >>>>> >>>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >>>>> >>>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", >>>>> >>>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>>> >>>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, >>>>> >>>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", >>>>> >>>>> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, >>>>> >>>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, >>>>> >>>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, >>>>> >>>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >>>>> >>>>> ++ } else { >>>>> >>>>> ++ fprintf(stdout, "\tVLAN ID = %d, Registered Mask = 0x%x, No Frag = %d\n", >>>>> >>>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>>> >>>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK, >>>>> >>>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x, Members = 0x%x\n", >>>>> >>>>> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + >>>>> >>>>> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), >>>>> >>>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, >>>>> >>>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, >>>>> >>>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >>>>> >>>>> ++ } >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++static void cpsw_ale_dump_outer_vlan_entry(int index, u32 *ale_entry) >>>>> >>>>> ++{ >>>>> >>>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>>> >>>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>>> >>>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: Outer VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", >>>>> >>>>> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, >>>>> >>>>> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); >>>>> >>>>> ++ >>>>> >>>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >>>>> >>>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", >>>>> >>>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>>> >>>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, >>>>> >>>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", >>>>> >>>>> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, >>>>> >>>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, >>>>> >>>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, >>>>> >>>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >>>>> >>>>> ++ } else { >>>>> >>>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", >>>>> >>>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>>> >>>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK, >>>>> >>>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x Members = 0x%x\n", >>>>> >>>>> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + >>>>> >>>>> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), >>>>> >>>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, >>>>> >>>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, >>>>> >>>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >>>>> >>>>> ++ } >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++static void cpsw_ale_dump_ethertype_entry(int index, u32 *ale_entry) >>>>> >>>>> ++{ >>>>> >>>>> ++ u16 ethertype = cpsw_ale_get_ethertype(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: VLAN Ethertype\n \tEthertype = 0x%x\n", index, ethertype); >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++static void cpsw_ale_dump_ipv4_entry(int index, u32 *ale_entry) >>>>> >>>>> ++{ >>>>> >>>>> ++ u8 ingress_bits = cpsw_ale_get_ingress_bits(ale_entry); >>>>> >>>>> ++ u32 ipv4_addr = cpsw_ale_get_ipv4_addr(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: VLAN IPv4\n \tIngress Bits: 0x%x IPv4 Address = %u.%u.%u.%u\n", >>>>> >>>>> ++ index, ingress_bits, ipv4_addr >> IPV4_ADDR_OCT1_SHIFT & IPV4_ADDR_MASK, >>>>> >>>>> ++ ipv4_addr >> IPV4_ADDR_OCT2_SHIFT & IPV4_ADDR_MASK, >>>>> >>>>> ++ ipv4_addr >> IPV4_ADDR_OCT3_SHIFT & IPV4_ADDR_MASK, ipv4_addr & IPV4_ADDR_MASK); >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++static void cpsw_ale_dump_ipv6_entry(int index, u32 *ale_entry) >>>>> >>>>> ++{ >>>>> >>>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>>> >>>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>>> >>>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ if (index & IPV6_HIGH_ENTRY_FLAG) { >>>>> >>>>> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Higher Entry (Lower Bit entry at %04u)\n \tIgnored Multicast bits: 0x%x, IPv6 Address (Bits [127:68]) = %04x:%03x%01x:%04x:%03x\n", >>>>> >>>>> ++ index, (index & (~IPV6_HIGH_ENTRY_FLAG)), >>>>> >>>>> ++ vlan_entry_word2 & IPV6_IGNMCBITS_MASK, >>>>> >>>>> ++ (vlan_entry_word1 >> IPV6_HADDR_W1_SHIFT) & IPV6_HADDR_W1_MASK_1, >>>>> >>>>> ++ vlan_entry_word1 & IPV6_HADDR_W1_MASK_2, >>>>> >>>>> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_1) & IPV6_HADDR_W0_MASK_1, >>>>> >>>>> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_2) & IPV6_HADDR_W0_MASK_2, >>>>> >>>>> ++ vlan_entry_word0 & IPV6_HADDR_W0_MASK_2); >>>>> >>>>> ++ } else { >>>>> >>>>> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Lower Entry (Higher Bit entry at %04u)\n \tIPv6 Address (Bits [127:68]) = %01x:%01x%03x:%04x:%04x:%04x\n", >>>>> >>>>> ++ index, (index | IPV6_HIGH_ENTRY_FLAG), >>>>> >>>>> ++ (vlan_entry_word2 >> IPV6_LADDR_W2_SHIFT) & IPV6_LADDR_W2_MAKS, >>>>> >>>>> ++ vlan_entry_word2 & IPV6_LADDR_W2_MAKS, >>>>> >>>>> ++ (vlan_entry_word1 >> IPV6_LADDR_W1_SHIFT) & IPV6_LADDR_W1_MASK_1, >>>>> >>>>> ++ vlan_entry_word1 & IPV6_LADDR_W1_MASK, >>>>> >>>>> ++ (vlan_entry_word0 >> IPV6_LADDR_W0_SHIFT) & IPV6_LADDR_W0_MASK, >>>>> >>>>> ++ vlan_entry_word0 & IPV6_LADDR_W0_MASK); >>>>> >>>>> ++ } >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry) >>>>> >>>>> ++{ >>>>> >>>>> ++ u8 addr[NUM_MAC_OCTET]; >>>>> >>>>> ++ int vlan = cpsw_ale_get_vlan_id(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ cpsw_ale_get_addr(ale_entry, addr); >>>>> >>>>> ++ if (cpsw_ale_get_mcast(ale_entry)) { >>>>> >>>>> ++ static const char * const str_mcast_state[] = {"Forwarding", >>>>> >>>>> ++ "Blocking/Forwarding/Learning", >>>>> >>>>> ++ "Learning/Forwarding", >>>>> >>>>> ++ "Forwarding"}; >>>>> >>>>> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >>>>> >>>>> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >>>>> >>>>> ++ u8 super = cpsw_ale_get_super(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: Multicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_state = %s, %s Super, port_mask = 0x%x\n", >>>>> >>>>> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], >>>>> >>>>> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >>>>> >>>>> ++ } else { >>>>> >>>>> ++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", >>>>> >>>>> ++ "Touched"}; >>>>> >>>>> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >>>>> >>>>> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >>>>> >>>>> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >>>>> >>>>> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >>>>> >>>>> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ int port_num; >>>>> >>>>> ++ >>>>> >>>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) >>>>> >>>>> ++ port_num = cpsw_ale_get_port_num_2g(ale_entry); >>>>> >>>>> ++ else if (rtl_version == CPSW3G_RTL_VERSION) >>>>> >>>>> ++ port_num = cpsw_ale_get_port_num_3g(ale_entry); >>>>> >>>>> ++ else >>>>> >>>>> ++ port_num = cpsw_ale_get_port_num(ale_entry); >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%d: Type: Unicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast_type = %s, port_num = 0x%x, Secure = %d, Blocked = %d, Touch = %d, Agable = %d\n", >>>>> >>>>> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], >>>>> >>>>> ++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); >>>>> >>>>> ++ } >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++void cpsw_dump_ale(struct k3_cpsw_regdump_hdr *ale_hdr, u32 *ale_pos) >>>>> >>>>> ++{ >>>>> >>>>> ++ int i, ale_entries; >>>>> >>>>> ++ >>>>> >>>>> ++ if (!ale_hdr) >>>>> >>>>> ++ return; >>>>> >>>>> ++ >>>>> >>>>> ++ ale_entries = (ale_hdr->len - sizeof(struct k3_cpsw_regdump_hdr)) / >>>>> >>>>> ++ ALE_ENTRY_WORDS / sizeof(u32); >>>>> >>>>> ++ >>>>> >>>>> ++ printf("Number of ALE entries: %d\n", ale_entries); >>>>> >>>>> ++ ale_pos += 2; >>>>> >>>>> ++ for (i = 0; i < ale_entries; i++) { >>>>> >>>>> ++ int type; >>>>> >>>>> ++ >>>>> >>>>> ++ type = cpsw_ale_get_entry_type(ale_pos); >>>>> >>>>> ++ >>>>> >>>>> ++ switch (type) { >>>>> >>>>> ++ case ALE_ENTRY_FREE: >>>>> >>>>> ++ break; >>>>> >>>>> ++ >>>>> >>>>> ++ case ALE_ENTRY_ADDR: >>>>> >>>>> ++ u32 oui_entry = cpsw_ale_get_oui_addr(ale_pos); >>>>> >>>>> ++ >>>>> >>>>> ++ if (oui_entry == 0x2) >>>>> >>>>> ++ cpsw_ale_dump_oui_entry(i, ale_pos); >>>>> >>>>> ++ else >>>>> >>>>> ++ cpsw_ale_dump_addr(i, ale_pos); >>>>> >>>>> ++ break; >>>>> >>>>> ++ >>>>> >>>>> ++ case ALE_ENTRY_VLAN: >>>>> >>>>> ++ u32 vlan_entry_type = cpsw_ale_get_vlan_entry_type(ale_pos); >>>>> >>>>> ++ >>>>> >>>>> ++ if (vlan_entry_type == VLAN_INNER_ENTRY) >>>>> >>>>> ++ cpsw_ale_dump_inner_vlan_entry(i, ale_pos); >>>>> >>>>> ++ else if (vlan_entry_type == VLAN_OUTER_ENTRY) >>>>> >>>>> ++ cpsw_ale_dump_outer_vlan_entry(i, ale_pos); >>>>> >>>>> ++ else if (vlan_entry_type == VLAN_ETHERTYPE_ENTRY) >>>>> >>>>> ++ cpsw_ale_dump_ethertype_entry(i, ale_pos); >>>>> >>>>> ++ else if (vlan_entry_type == VLAN_IPV4_ENTRY) >>>>> >>>>> ++ cpsw_ale_dump_ipv4_entry(i, ale_pos); >>>>> >>>>> ++ else if (vlan_entry_type & VLAN_IPV6_ENTRY_MASK) >>>>> >>>>> ++ cpsw_ale_dump_ipv6_entry(i, ale_pos); >>>>> >>>>> ++ break; >>>>> >>>>> ++ >>>>> >>>>> ++ case ALE_ENTRY_VLAN_ADDR: >>>>> >>>>> ++ cpsw_ale_dump_vlan_addr(i, ale_pos); >>>>> >>>>> ++ break; >>>>> >>>>> ++ >>>>> >>>>> ++ default: >>>>> >>>>> ++ break; >>>>> >>>>> ++ } >>>>> >>>>> ++ >>>>> >>>>> ++ ale_pos += ALE_ENTRY_WORDS; >>>>> >>>>> ++ } >>>>> >>>>> ++} >>>>> >>>>> ++ >>>>> >>>>> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused, >>>>> >>>>> ++ struct ethtool_regs *regs) >>>>> >>>>> ++{ >>>>> >>>>> ++ struct k3_cpsw_regdump_hdr *dump_hdr, *ale_hdr = NULL; >>>>> >>>>> ++ u32 *reg = (u32 *)regs->data, *ale_pos; >>>>> >>>>> ++ u32 mod_id; >>>>> >>>>> ++ int i, regdump_len = info->regdump_len; >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "K3 CPSW dump version: %d, len: %d\n", >>>>> >>>>> ++ regs->version, info->regdump_len); >>>>> >>>>> ++ fprintf(stdout, "(Missing registers in memory space can be considered as zero valued)\n"); >>>>> >>>>> ++ >>>>> >>>>> ++ /* Line break before register dump */ >>>>> >>>>> ++ fprintf(stdout, "--------------------------------------------------------------------\n"); >>>>> >>>>> ++ i = 0; >>>>> >>>>> ++ do { >>>>> >>>>> ++ u32 *tmp, j; >>>>> >>>>> ++ u32 num_items; >>>>> >>>>> ++ >>>>> >>>>> ++ dump_hdr = (struct k3_cpsw_regdump_hdr *)reg; >>>>> >>>>> ++ mod_id = dump_hdr->module_id; >>>>> >>>>> ++ >>>>> >>>>> ++ num_items = dump_hdr->len / sizeof(u32); >>>>> >>>>> ++ >>>>> >>>>> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE) >>>>> >>>>> ++ rtl_version = reg[3] & RTL_VERSION_MASK; >>>>> >>>>> ++ >>>>> >>>>> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { >>>>> >>>>> ++ ale_hdr = dump_hdr; >>>>> >>>>> ++ ale_pos = reg; >>>>> >>>>> ++ break; >>>>> >>>>> ++ } >>>>> >>>>> ++ >>>>> >>>>> ++ fprintf(stdout, "%s regdump: number of Registers:(%d)\n", >>>>> >>>>> ++ mod_names[mod_id], num_items - 2); >>>>> >>>>> ++ tmp = reg; >>>>> >>>>> ++ /* Values are stored in pair as reg_offset-reg_val, hence parse the same way*/ >>>>> >>>>> ++ for (j = 2; j < num_items; j += 2) { >>>>> >>>>> ++ if (tmp[j + 1] != 0x0) >>>>> >>>>> ++ fprintf(stdout, "%08x:reg(%08X)\n", tmp[j], tmp[j + 1]); >>>>> >>>>> ++ } >>>>> >>>>> ++ >>>>> >>>>> ++ reg += num_items; >>>>> >>>>> ++ i += dump_hdr->len; >>>>> >>>>> ++ } while (i < regdump_len); >>>>> >>>>> ++ >>>>> >>>>> ++ /* Adding a boundary in between Register dump and ALE table */ >>>>> >>>>> ++ fprintf(stdout, "--------------------------\n"); >>>>> >>>>> ++ >>>>> >>>>> ++ cpsw_dump_ale(ale_hdr, ale_pos); >>>>> >>>>> ++ >>>>> >>>>> ++ return 0; >>>>> >>>>> ++}; >>>>> >>>>> +diff --git a/ethtool.c b/ethtool.c >>>>> >>>>> +index 3ac15a7..a383eb6 100644 >>>>> >>>>> +--- a/ethtool.c >>>>> >>>>> ++++ b/ethtool.c >>>>> >>>>> +@@ -1162,6 +1162,7 @@ static const struct { >>>>> >>>>> + { "fsl_enetc", fsl_enetc_dump_regs }, >>>>> >>>>> + { "fsl_enetc_vf", fsl_enetc_dump_regs }, >>>>> >>>>> + { "hns3", hns3_dump_regs }, >>>>> >>>>> ++ { "am65-cpsw-nuss", am65_cpsw_dump_regs }, >>>>> >>>>> + }; >>>>> >>>>> + #endif >>>>> >>>>> + >>>>> >>>>> +diff --git a/internal.h b/internal.h >>>>> >>>>> +index 4b994f5..81212b4 100644 >>>>> >>>>> +--- a/internal.h >>>>> >>>>> ++++ b/internal.h >>>>> >>>>> +@@ -410,4 +410,7 @@ int cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); >>>>> >>>>> + /* Microchip Ethernet Controller */ >>>>> >>>>> + int lan743x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); >>>>> >>>>> + >>>>> >>>>> ++/* TI K3 CPSW Ethernet Switch */ >>>>> >>>>> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); >>>>> >>>>> ++ >>>>> >>>>> + #endif /* ETHTOOL_INTERNAL_H__ */ >>>>> >>>>> +-- >>>>> >>>>> +2.34.1 >>>>> >>>>> + >>>>> >>>>> diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>>> new file mode 100644 >>>>> index 00000000..3b388151 >>>>> --- /dev/null >>>>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>>> @@ -0,0 +1,4 @@ >>>>> +ETHTOOL_ARAGO = "" >>>>> +ETHTOOL_ARAGO:arago = "ethtool-arago.inc" >>>>> + >>>>> +require ${ETHTOOL_ARAGO} >>>>> -- >>>>> 2.34.1 >>> >>> >>> >>> >>> >
On 7/11/2025 1:10 PM, Andrew Davis wrote: > On 7/11/25 12:31 PM, Ryan Eatmon via lists.yoctoproject.org wrote: >> >> >> On 7/10/2025 9:35 PM, Aniket Limaye wrote: >>> Denys, Ryan, >>> >>> On 11/07/25 07:04, Aniket Limaye via lists.yoctoproject.org wrote: >>>> >>>> >>>> On 11/07/25 06:02, Denys Dmytriyenko wrote: >>>>> I wonder if the patch itself is malformed - specifically if it has >>>>> windows >>>>> newlines that result in interlaced empty lines in mutt on Linux, as >>>>> seen >>>>> below. While .inc and .bbappend seem fine. >>>>> >>>> >>>> Chintan, Yeah looks like the patchfile I added was not properly >>>> formatted. I will try resending this one quickly. >>>> >>> >>> Not sure what caused the weird encoding in the first place... >>> >>> Sent v2 here: https://lists.yoctoproject.org/g/meta-arago/message/16282 >> >> What's really odd is that applying the v1 patch resulted in a >> perfectly fine file in the repo. I applied this patch yesterday and >> the patch file looks fine. Or am I wrong. The issue is that this >> patch is already on next and is going through CICD promotion right >> now. If this is a problem we may need to submit a follow on patch to >> fix it. Can someone check the current file in the repo and verify? >> >> > > $ git checkout 83558083 > $ file > meta-arago-distro/recipes-extended/ethtool/ethtool/0001-pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch > meta-arago-distro/recipes-extended/ethtool/ethtool/0001-pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch: unified diff output, ASCII text > > Looks fine to me, all those odd newlines must have been removed by > whatever tool you used to apply the email. I fetch the files from patchwork and then use git -am to apply them. So patchwork must be fixing it up. > Andrew > >> >>> >>>> Thanks, >>>> Aniket >>>> >>>>> >>>>> On Mon, Jul 07, 2025 at 02:37:20PM +0530, Aniket Limaye via >>>>> lists.yoctoproject.org wrote: >>>>>> Add support for TI K3 CPSW register and ALE table dump through the >>>>>> ethtool userspace utility. >>>>>> >>>>>> Signed-off-by: Aniket Limaye <a-limaye@ti.com> >>>>>> --- >>>>>> .../ethtool/ethtool-arago.inc | 8 + >>>>>> ...k3-cpsw-registers-and-ale-table-dump.patch | 574 >>>>>> ++++++++++++++++++ >>>>>> .../ethtool/ethtool_%.bbappend | 4 + >>>>>> 3 files changed, 586 insertions(+) >>>>>> create mode 100644 >>>>>> meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>>>> create mode 100644 >>>>>> meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>>>> create mode 100644 >>>>>> meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>>>> >>>>>> diff --git >>>>>> a/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>>>> b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>>>> new file mode 100644 >>>>>> index 00000000..5fd05a85 >>>>>> --- /dev/null >>>>>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc >>>>>> @@ -0,0 +1,8 @@ >>>>>> +PR:append = ".arago0" >>>>>> + >>>>>> +FILESEXTRAPATHS:prepend := "${THISDIR}/ethtool:" >>>>>> + >>>>>> +SRC_URI:append = " \ >>>>>> + >>>>>> file://pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch \ >>>>>> + " >>>>>> + >>>>>> diff --git >>>>>> a/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>>>> new file mode 100644 >>>>>> index 00000000..a14089b4 >>>>>> --- /dev/null >>>>>> +++ >>>>>> b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch >>>>>> @@ -0,0 +1,574 @@ >>>>>> +From: Chintan Vankar <c-vankar@ti.com> >>>>>> >>>>>> +Subject: [PATCH] pretty: Add support for TI K3 CPSW registers and >>>>>> ALE table dump >>>>>> >>>>>> +Date: Thu, 3 Jul 2025 12:02:46 +0530 >>>>>> >>>>>> + >>>>>> >>>>>> +Add support to dump CPSW registers and ALE table for the CPSW >>>>>> instances on >>>>>> >>>>>> +K3 SoCs that are configured using the am65-cpsw-nuss.c >>>>>> device-driver in >>>>>> >>>>>> +Linux. >>>>>> >>>>>> + >>>>>> >>>>>> +Upstream-Status: Submitted >>>>>> [https://lore.kernel.org/all/20250705134807.3514891-1-c-vankar@ti.com/] >>>>>> >>>>>> +Signed-off-by: Chintan Vankar <c-vankar@ti.com> >>>>>> >>>>>> +--- >>>>>> >>>>>> + Makefile.am | 2 +- >>>>>> >>>>>> + am65-cpsw-nuss.c | 510 >>>>>> +++++++++++++++++++++++++++++++++++++++++++++++ >>>>>> >>>>>> + ethtool.c | 1 + >>>>>> >>>>>> + internal.h | 3 + >>>>>> >>>>>> + 4 files changed, 515 insertions(+), 1 deletion(-) >>>>>> >>>>>> + create mode 100644 am65-cpsw-nuss.c >>>>>> >>>>>> + >>>>>> >>>>>> +diff --git a/Makefile.am b/Makefile.am >>>>>> >>>>>> +index b9e06ad..fe6afcb 100644 >>>>>> >>>>>> +--- a/Makefile.am >>>>>> >>>>>> ++++ b/Makefile.am >>>>>> >>>>>> +@@ -23,7 +23,7 @@ ethtool_SOURCES += \ >>>>>> >>>>>> + smsc911x.c at76c50x-usb.c sfc.c stmmac.c \ >>>>>> >>>>>> + sff-common.c sff-common.h sfpid.c sfpdiag.c \ >>>>>> >>>>>> + ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c >>>>>> lan78xx.c \ >>>>>> >>>>>> +- igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c >>>>>> >>>>>> ++ igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c >>>>>> am65-cpsw-nuss.c >>>>>> >>>>>> + endif >>>>>> >>>>>> + >>>>>> >>>>>> + if ENABLE_BASH_COMPLETION >>>>>> >>>>>> +diff --git a/am65-cpsw-nuss.c b/am65-cpsw-nuss.c >>>>>> >>>>>> +new file mode 100644 >>>>>> >>>>>> +index 0000000..de8e3e9 >>>>>> >>>>>> +--- /dev/null >>>>>> >>>>>> ++++ b/am65-cpsw-nuss.c >>>>>> >>>>>> +@@ -0,0 +1,510 @@ >>>>>> >>>>>> ++// SPDX-License-Identifier: GPL-2.0-only OR MIT >>>>>> >>>>>> ++/* Code to dump registers and ALE table for the CPSW instances >>>>>> on K3 SoCs that are configured using >>>>>> >>>>>> ++ * the am65-cpsw-nuss device-driver in Linux. >>>>>> >>>>>> ++ * >>>>>> >>>>>> ++ * Copyright (C) 2025 Texas Instruments >>>>>> >>>>>> ++ * Author: Chintan Vankar <c-vankar@ti.com> >>>>>> >>>>>> ++ */ >>>>>> >>>>>> ++ >>>>>> >>>>>> ++#include <stdio.h> >>>>>> >>>>>> ++#include <string.h> >>>>>> >>>>>> ++ >>>>>> >>>>>> ++#include "internal.h" >>>>>> >>>>>> ++ >>>>>> >>>>>> ++#define ALE_ENTRY_BITS 74 >>>>>> >>>>>> ++#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) >>>>>> >>>>>> ++ >>>>>> >>>>>> ++#define ALE_ENTRY_FREE 0x0 >>>>>> >>>>>> ++#define ALE_ENTRY_ADDR 0x1 >>>>>> >>>>>> ++#define ALE_ENTRY_VLAN 0x2 >>>>>> >>>>>> ++#define ALE_ENTRY_VLAN_ADDR 0x3 >>>>>> >>>>>> ++ >>>>>> >>>>>> ++#define BIT(nr) (1 << (nr)) >>>>>> >>>>>> ++#define BITMASK(bits) (BIT(bits) - 1) >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/* ALE word specifiers */ >>>>>> >>>>>> ++#define NUM_ALE_WORDS 2 >>>>>> >>>>>> ++#define ALE_WORD_LEN 32 >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/* MAC address specifiers */ >>>>>> >>>>>> ++#define MAC_START_BIT 40 >>>>>> >>>>>> ++#define MAC_OCTET_LEN 8 >>>>>> >>>>>> ++#define NUM_MAC_OCTET 6 >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/* RTL version specifiers */ >>>>>> >>>>>> ++#define RTL_VERSION_MASK 0xF800 >>>>>> >>>>>> ++#define CPSW2G_RTL_VERSION 0x3800 >>>>>> >>>>>> ++#define CPSW3G_RTL_VERSION 0x0 >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/* OUI address uses format xx:xx:xx, use OUI shift as 16 bits >>>>>> and MASK as 0xFF to parse the same*/ >>>>>> >>>>>> ++#define OUI_ADDR_SHIFT 16 >>>>>> >>>>>> ++#define OUI_ADDR_MASK 0xFF >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/* VLAN entry specifiers */ >>>>>> >>>>>> ++#define VLAN_INNER_ENTRY 0x0 >>>>>> >>>>>> ++#define VLAN_OUTER_ENTRY 0x2 >>>>>> >>>>>> ++#define VLAN_ETHERTYPE_ENTRY 0x4 >>>>>> >>>>>> ++#define VLAN_IPV4_ENTRY 0x6 >>>>>> >>>>>> ++#define VLAN_IPV6_ENTRY_MASK 0x1 >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/* VLAN Inner/Outer table entry MASKs and SHIFTs*/ >>>>>> >>>>>> ++#define NOLEARN_FLAG_SHIFT 2 >>>>>> >>>>>> ++#define NOLEARN_FLAG_MASK 0x1FF >>>>>> >>>>>> ++#define INGRESS_CHECK_SHIFT 1 >>>>>> >>>>>> ++#define INGRESS_CHECK_MASK 0x1 >>>>>> >>>>>> ++#define VLAN_ID_SHIFT 16 >>>>>> >>>>>> ++#define VLAN_ID_MASK 0xFFF >>>>>> >>>>>> ++#define NOFRAG_FLAG_SHIFT_2G 12 >>>>>> >>>>>> ++#define NOFRAG_FLAG_MASK_2G 0x1 >>>>>> >>>>>> ++#define NOFRAG_FLAG_SHIFT 15 >>>>>> >>>>>> ++#define NOFRAG_FLAG_MASK 0x1 >>>>>> >>>>>> ++#define REG_MASK_SHIFT 4 >>>>>> >>>>>> ++#define REG_MASK_MASK 0x1FF >>>>>> >>>>>> ++#define PKT_EGRESS_W1_MASK 0x1 >>>>>> >>>>>> ++#define PKT_EGRESS_W1_OFFSET 512 >>>>>> >>>>>> ++#define PKT_EGRESS_SHIFT 24 >>>>>> >>>>>> ++#define PKT_EGRESS_MASK_2G 0x3 >>>>>> >>>>>> ++#define PKT_EGRESS_MASK 0x1FF >>>>>> >>>>>> ++#define UNREG_MASK_SHIFT_2G 20 >>>>>> >>>>>> ++#define UNREG_MASK_MASK_2G 0x7 >>>>>> >>>>>> ++#define UNREG_MASK_SHIFT 12 >>>>>> >>>>>> ++#define UNREG_MASK_MASK 0x1FF >>>>>> >>>>>> ++#define NXT_HDR_CTRL_SHIFT_2G 19 >>>>>> >>>>>> ++#define NXT_HDR_CTRL_MASK_2G 0x1 >>>>>> >>>>>> ++#define NXT_HDR_CTRL_SHIFT 23 >>>>>> >>>>>> ++#define NXT_HDR_CTRL_MASK 0x1 >>>>>> >>>>>> ++#define VLAN_MEMBER_LIST_MASK_2G 0x3 >>>>>> >>>>>> ++#define VLAN_MEMBER_LIST_MASK 0x1FF >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/* VLAN IPv4 entry MASKs and SHIFTs*/ >>>>>> >>>>>> ++#define IPV4_ADDR_OCT1_SHIFT 24 >>>>>> >>>>>> ++#define IPV4_ADDR_OCT2_SHIFT 16 >>>>>> >>>>>> ++#define IPV4_ADDR_OCT3_SHIFT 8 >>>>>> >>>>>> ++#define IPV4_ADDR_MASK 0xFF >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/* VLAN IPv6 entry MASKs and SHIFTs*/ >>>>>> >>>>>> ++#define IPV6_HIGH_ENTRY_FLAG 0x40 >>>>>> >>>>>> ++#define IPV6_IGNMCBITS_MASK 0xFF >>>>>> >>>>>> ++#define IPV6_HADDR_W1_SHIFT 12 >>>>>> >>>>>> ++#define IPV6_HADDR_W1_MASK_1 0xFFFF >>>>>> >>>>>> ++#define IPV6_HADDR_W1_MASK_2 0xFFF >>>>>> >>>>>> ++#define IPV6_HADDR_W0_SHIFT_1 28 >>>>>> >>>>>> ++#define IPV6_HADDR_W0_MASK_1 0xF >>>>>> >>>>>> ++#define IPV6_HADDR_W0_SHIFT_2 12 >>>>>> >>>>>> ++#define IPV6_HADDR_W0_MASK_2 0xFFFF >>>>>> >>>>>> ++#define IPV6_LADDR_W2_SHIFT 4 >>>>>> >>>>>> ++#define IPV6_LADDR_W2_MAKS 0xF >>>>>> >>>>>> ++#define IPV6_LADDR_W1_SHIFT 16 >>>>>> >>>>>> ++#define IPV6_LADDR_W1_MASK_1 0xFFF >>>>>> >>>>>> ++#define IPV6_LADDR_W1_MASK 0xFFFF >>>>>> >>>>>> ++#define IPV6_LADDR_W0_SHIFT 16 >>>>>> >>>>>> ++#define IPV6_LADDR_W0_MASK 0xFFFF >>>>>> >>>>>> ++ >>>>>> >>>>>> ++/** >>>>>> >>>>>> ++ * Since there are different instances of CPSW (namely cpsw2g, >>>>>> cpsw3g, cpsw5g and cpsw9g) >>>>>> >>>>>> ++ * some register offsets differ to get some parameters for ALE >>>>>> table, parse rtl_version >>>>>> >>>>>> ++ * from ALE_MOD_VER register to determine which instance is >>>>>> being used. >>>>>> >>>>>> ++ */ >>>>>> >>>>>> ++u32 rtl_version; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, >>>>>> u32 bits) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ int idx; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ idx = start / ALE_WORD_LEN; >>>>>> >>>>>> ++ start -= idx * ALE_WORD_LEN; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ /** >>>>>> >>>>>> ++ * ALE words are stored in order word2, word1 and word0, >>>>>> flip the word to parse in numeric >>>>>> >>>>>> ++ * order >>>>>> >>>>>> ++ */ >>>>>> >>>>>> ++ idx = NUM_ALE_WORDS - idx; /* flip */ >>>>>> >>>>>> ++ return (ale_entry[idx] >> start) & BITMASK(bits); >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++#define DEFINE_ALE_FIELD(name, start, bits) \ >>>>>> >>>>>> ++static inline int cpsw_ale_get_##name(u32 *ale_entry) \ >>>>>> >>>>>> ++{ \ >>>>>> >>>>>> ++ return cpsw_ale_get_field(ale_entry, start, bits); \ >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++DEFINE_ALE_FIELD(entry_type, 60, 2) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(vlan_id, 48, 12) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(mcast_state, 62, 2) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(port_mask, 66, 9) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(super, 65, 1) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(agable, 62, 1) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(touched, 63, 1) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(ucast_type, 62, 2) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(port_num, 66, 4) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(port_num_2g, 66, 1) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(port_num_3g, 66, 2) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(blocked, 65, 1) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(secure, 64, 1) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(oui_entry, 62, 2) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(oui_addr, 4, 24) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(mcast, 40, 1) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(vlan_entry_type, 62, 3) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(ethertype, 0, 16) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(ipv4_addr, 0, 32) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(ingress_bits, 65, 5) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(ipv6_addr_low, 0, 60) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(ipv6_addr_mid, 63, 8) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(ipv6_addr_high, 0, 60) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(entry_word0, 0, 32) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(entry_word1, 32, 32) >>>>>> >>>>>> ++DEFINE_ALE_FIELD(entry_word2, 64, 12) >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ int i; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ for (i = 0; i < NUM_MAC_OCTET; i++) >>>>>> >>>>>> ++ addr[i] = cpsw_ale_get_field(ale_entry, MAC_START_BIT - >>>>>> MAC_OCTET_LEN * i, >>>>>> >>>>>> ++ MAC_OCTET_LEN); >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++struct k3_cpsw_regdump_hdr { >>>>>> >>>>>> ++ u32 module_id; >>>>>> >>>>>> ++ u32 len; >>>>>> >>>>>> ++}; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++enum { >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_NUSS = 1, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_MDIO = 3, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW = 4, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_P0 = 5, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_PN = 6, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE = 8, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, >>>>>> >>>>>> ++ K3_CPSW_REGDUMP_MOD_LAST, >>>>>> >>>>>> ++}; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static const char *mod_names[K3_CPSW_REGDUMP_MOD_LAST] = { >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_NUSS] = "cpsw-nuss", >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_RGMII_STATUS] = "cpsw-nuss-rgmii-status", >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_MDIO] = "cpsw-nuss-mdio", >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW] = "cpsw-nu", >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_P0] = "cpsw-nu-p0", >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_PN] = "cpsw-nu-pn", >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_CPTS] = "cpsw-nu-cpts", >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE] = "cpsw-nu-ale", >>>>>> >>>>>> ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL] = "cpsw-nu-ale-tbl", >>>>>> >>>>>> ++}; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static void cpsw_ale_dump_oui_entry(int index, u32 *ale_entry) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ u32 oui_addr; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ oui_addr = cpsw_ale_get_oui_addr(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: OUI Unicast\n, \tOUI = >>>>>> %02x:%02x:%02x\n", >>>>>> >>>>>> ++ index, (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, >>>>>> >>>>>> ++ (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, oui_addr & >>>>>> OUI_ADDR_MASK); >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static void cpsw_ale_dump_addr(int index, u32 *ale_entry) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ u8 addr[NUM_MAC_OCTET]; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ cpsw_ale_get_addr(ale_entry, addr); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (cpsw_ale_get_mcast(ale_entry)) { >>>>>> >>>>>> ++ static const char * const str_mcast_state[] = >>>>>> {"Forwarding", >>>>>> >>>>>> ++ "Blocking/Forwarding/Learning", >>>>>> >>>>>> ++ "Learning/Forwarding", >>>>>> >>>>>> ++ "Forwarding"}; >>>>>> >>>>>> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >>>>>> >>>>>> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >>>>>> >>>>>> ++ u8 super = cpsw_ale_get_super(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: Multicast\n \tAddress = >>>>>> %02x:%02x:%02x:%02x:%02x:%02x, Multicast_State = %s, %sSuper, >>>>>> port_mask = 0x%x\n", >>>>>> >>>>>> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], >>>>>> addr[5], >>>>>> >>>>>> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >>>>>> >>>>>> ++ } else { >>>>>> >>>>>> ++ static const char * const s_ucast_type[] = >>>>>> {"Persistent", "Untouched", "OUI", >>>>>> >>>>>> ++ "Touched"}; >>>>>> >>>>>> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >>>>>> >>>>>> ++ u8 port_num = cpsw_ale_get_port_num(ale_entry); >>>>>> >>>>>> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >>>>>> >>>>>> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >>>>>> >>>>>> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >>>>>> >>>>>> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: Unicast\n \tUpdated Address = >>>>>> %02x:%02x:%02x:%02x:%02x:%02x, Unicast Type = %s, Port_num = 0x%x, >>>>>> Secure: %d, Blocked: %d, Touch = %d, Agable = %d\n", >>>>>> >>>>>> ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], >>>>>> addr[5], >>>>>> >>>>>> ++ s_ucast_type[ucast_type], port_num, secure, blocked, >>>>>> touched, agable); >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static void cpsw_ale_dump_inner_vlan_entry(int index, u32 >>>>>> *ale_entry) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>>>> >>>>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>>>> >>>>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: Inner VLAN\n \tNolearn Mask = >>>>>> 0x%x, Ingress Check = %d\n", >>>>>> >>>>>> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & >>>>>> NOLEARN_FLAG_MASK, >>>>>> >>>>>> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & >>>>>> INGRESS_CHECK_MASK); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >>>>>> >>>>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, >>>>>> Registered Mask = 0x%x\n", >>>>>> >>>>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>>>> >>>>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & >>>>>> NOFRAG_FLAG_MASK_2G, >>>>>> >>>>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>>>>> Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members >>>>>> = 0x%x\n", >>>>>> >>>>>> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>>>>> PKT_EGRESS_MASK_2G, >>>>>> >>>>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & >>>>>> UNREG_MASK_MASK_2G, >>>>>> >>>>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & >>>>>> NXT_HDR_CTRL_MASK_2G, >>>>>> >>>>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >>>>>> >>>>>> ++ } else { >>>>>> >>>>>> ++ fprintf(stdout, "\tVLAN ID = %d, Registered Mask = 0x%x, >>>>>> No Frag = %d\n", >>>>>> >>>>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>>>> >>>>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK, >>>>>> >>>>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & >>>>>> NOFRAG_FLAG_MASK); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>>>>> Limit Next Header Control = %d, Unregistered Mask = 0x%x, Members >>>>>> = 0x%x\n", >>>>>> >>>>>> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * >>>>>> PKT_EGRESS_W1_OFFSET + >>>>>> >>>>>> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>>>>> PKT_EGRESS_MASK), >>>>>> >>>>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & >>>>>> NXT_HDR_CTRL_MASK, >>>>>> >>>>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & >>>>>> UNREG_MASK_MASK, >>>>>> >>>>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static void cpsw_ale_dump_outer_vlan_entry(int index, u32 >>>>>> *ale_entry) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>>>> >>>>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>>>> >>>>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: Outer VLAN\n \tNolearn Mask = >>>>>> 0x%x, Ingress Check = %d\n", >>>>>> >>>>>> ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & >>>>>> NOLEARN_FLAG_MASK, >>>>>> >>>>>> ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & >>>>>> INGRESS_CHECK_MASK); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) { >>>>>> >>>>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, >>>>>> Registered Mask = 0x%x\n", >>>>>> >>>>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>>>> >>>>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & >>>>>> NOFRAG_FLAG_MASK_2G, >>>>>> >>>>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>>>>> Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members >>>>>> = 0x%x\n", >>>>>> >>>>>> ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>>>>> PKT_EGRESS_MASK_2G, >>>>>> >>>>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & >>>>>> UNREG_MASK_MASK_2G, >>>>>> >>>>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & >>>>>> NXT_HDR_CTRL_MASK_2G, >>>>>> >>>>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); >>>>>> >>>>>> ++ } else { >>>>>> >>>>>> ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, >>>>>> Registered Mask = 0x%x\n", >>>>>> >>>>>> ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, >>>>>> >>>>>> ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & >>>>>> NOFRAG_FLAG_MASK, >>>>>> >>>>>> ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, >>>>>> Limit Next Header Control = %d, Unregistered Mask = 0x%x Members = >>>>>> 0x%x\n", >>>>>> >>>>>> ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * >>>>>> PKT_EGRESS_W1_OFFSET + >>>>>> >>>>>> ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & >>>>>> PKT_EGRESS_MASK), >>>>>> >>>>>> ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & >>>>>> NXT_HDR_CTRL_MASK, >>>>>> >>>>>> ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & >>>>>> UNREG_MASK_MASK, >>>>>> >>>>>> ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static void cpsw_ale_dump_ethertype_entry(int index, u32 >>>>>> *ale_entry) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ u16 ethertype = cpsw_ale_get_ethertype(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: VLAN Ethertype\n \tEthertype = >>>>>> 0x%x\n", index, ethertype); >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static void cpsw_ale_dump_ipv4_entry(int index, u32 *ale_entry) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ u8 ingress_bits = cpsw_ale_get_ingress_bits(ale_entry); >>>>>> >>>>>> ++ u32 ipv4_addr = cpsw_ale_get_ipv4_addr(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: VLAN IPv4\n \tIngress Bits: 0x%x >>>>>> IPv4 Address = %u.%u.%u.%u\n", >>>>>> >>>>>> ++ index, ingress_bits, ipv4_addr >> IPV4_ADDR_OCT1_SHIFT & >>>>>> IPV4_ADDR_MASK, >>>>>> >>>>>> ++ ipv4_addr >> IPV4_ADDR_OCT2_SHIFT & IPV4_ADDR_MASK, >>>>>> >>>>>> ++ ipv4_addr >> IPV4_ADDR_OCT3_SHIFT & IPV4_ADDR_MASK, >>>>>> ipv4_addr & IPV4_ADDR_MASK); >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static void cpsw_ale_dump_ipv6_entry(int index, u32 *ale_entry) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); >>>>>> >>>>>> ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); >>>>>> >>>>>> ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (index & IPV6_HIGH_ENTRY_FLAG) { >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Higher Entry (Lower >>>>>> Bit entry at %04u)\n \tIgnored Multicast bits: 0x%x, IPv6 Address >>>>>> (Bits [127:68]) = %04x:%03x%01x:%04x:%03x\n", >>>>>> >>>>>> ++ index, (index & (~IPV6_HIGH_ENTRY_FLAG)), >>>>>> >>>>>> ++ vlan_entry_word2 & IPV6_IGNMCBITS_MASK, >>>>>> >>>>>> ++ (vlan_entry_word1 >> IPV6_HADDR_W1_SHIFT) & >>>>>> IPV6_HADDR_W1_MASK_1, >>>>>> >>>>>> ++ vlan_entry_word1 & IPV6_HADDR_W1_MASK_2, >>>>>> >>>>>> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_1) & >>>>>> IPV6_HADDR_W0_MASK_1, >>>>>> >>>>>> ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_2) & >>>>>> IPV6_HADDR_W0_MASK_2, >>>>>> >>>>>> ++ vlan_entry_word0 & IPV6_HADDR_W0_MASK_2); >>>>>> >>>>>> ++ } else { >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: VLAN IPv6 Lower Entry (Higher >>>>>> Bit entry at %04u)\n \tIPv6 Address (Bits [127:68]) = >>>>>> %01x:%01x%03x:%04x:%04x:%04x\n", >>>>>> >>>>>> ++ index, (index | IPV6_HIGH_ENTRY_FLAG), >>>>>> >>>>>> ++ (vlan_entry_word2 >> IPV6_LADDR_W2_SHIFT) & >>>>>> IPV6_LADDR_W2_MAKS, >>>>>> >>>>>> ++ vlan_entry_word2 & IPV6_LADDR_W2_MAKS, >>>>>> >>>>>> ++ (vlan_entry_word1 >> IPV6_LADDR_W1_SHIFT) & >>>>>> IPV6_LADDR_W1_MASK_1, >>>>>> >>>>>> ++ vlan_entry_word1 & IPV6_LADDR_W1_MASK, >>>>>> >>>>>> ++ (vlan_entry_word0 >> IPV6_LADDR_W0_SHIFT) & >>>>>> IPV6_LADDR_W0_MASK, >>>>>> >>>>>> ++ vlan_entry_word0 & IPV6_LADDR_W0_MASK); >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ u8 addr[NUM_MAC_OCTET]; >>>>>> >>>>>> ++ int vlan = cpsw_ale_get_vlan_id(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ cpsw_ale_get_addr(ale_entry, addr); >>>>>> >>>>>> ++ if (cpsw_ale_get_mcast(ale_entry)) { >>>>>> >>>>>> ++ static const char * const str_mcast_state[] = >>>>>> {"Forwarding", >>>>>> >>>>>> ++ "Blocking/Forwarding/Learning", >>>>>> >>>>>> ++ "Learning/Forwarding", >>>>>> >>>>>> ++ "Forwarding"}; >>>>>> >>>>>> ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); >>>>>> >>>>>> ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); >>>>>> >>>>>> ++ u8 super = cpsw_ale_get_super(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: Multicast\n \tVID = %d, >>>>>> Address = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_state = %s, %s >>>>>> Super, port_mask = 0x%x\n", >>>>>> >>>>>> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], >>>>>> addr[4], addr[5], >>>>>> >>>>>> ++ str_mcast_state[state], super ? "" : "No ", port_mask); >>>>>> >>>>>> ++ } else { >>>>>> >>>>>> ++ static const char * const s_ucast_type[] = >>>>>> {"Persistent", "Untouched", "OUI", >>>>>> >>>>>> ++ "Touched"}; >>>>>> >>>>>> ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); >>>>>> >>>>>> ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); >>>>>> >>>>>> ++ u8 touched = cpsw_ale_get_touched(ale_entry); >>>>>> >>>>>> ++ u8 secure = cpsw_ale_get_secure(ale_entry); >>>>>> >>>>>> ++ u8 agable = cpsw_ale_get_agable(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ int port_num; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (rtl_version == CPSW2G_RTL_VERSION) >>>>>> >>>>>> ++ port_num = cpsw_ale_get_port_num_2g(ale_entry); >>>>>> >>>>>> ++ else if (rtl_version == CPSW3G_RTL_VERSION) >>>>>> >>>>>> ++ port_num = cpsw_ale_get_port_num_3g(ale_entry); >>>>>> >>>>>> ++ else >>>>>> >>>>>> ++ port_num = cpsw_ale_get_port_num(ale_entry); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%d: Type: Unicast\n \tVID = %d, Address >>>>>> = %02x:%02x:%02x:%02x:%02x:%02x, Unicast_type = %s, port_num = >>>>>> 0x%x, Secure = %d, Blocked = %d, Touch = %d, Agable = %d\n", >>>>>> >>>>>> ++ index, vlan, addr[0], addr[1], addr[2], addr[3], >>>>>> addr[4], addr[5], >>>>>> >>>>>> ++ s_ucast_type[ucast_type], port_num, secure, blocked, >>>>>> touched, agable); >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++void cpsw_dump_ale(struct k3_cpsw_regdump_hdr *ale_hdr, u32 >>>>>> *ale_pos) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ int i, ale_entries; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (!ale_hdr) >>>>>> >>>>>> ++ return; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ ale_entries = (ale_hdr->len - sizeof(struct >>>>>> k3_cpsw_regdump_hdr)) / >>>>>> >>>>>> ++ ALE_ENTRY_WORDS / sizeof(u32); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ printf("Number of ALE entries: %d\n", ale_entries); >>>>>> >>>>>> ++ ale_pos += 2; >>>>>> >>>>>> ++ for (i = 0; i < ale_entries; i++) { >>>>>> >>>>>> ++ int type; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ type = cpsw_ale_get_entry_type(ale_pos); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ switch (type) { >>>>>> >>>>>> ++ case ALE_ENTRY_FREE: >>>>>> >>>>>> ++ break; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ case ALE_ENTRY_ADDR: >>>>>> >>>>>> ++ u32 oui_entry = cpsw_ale_get_oui_addr(ale_pos); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (oui_entry == 0x2) >>>>>> >>>>>> ++ cpsw_ale_dump_oui_entry(i, ale_pos); >>>>>> >>>>>> ++ else >>>>>> >>>>>> ++ cpsw_ale_dump_addr(i, ale_pos); >>>>>> >>>>>> ++ break; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ case ALE_ENTRY_VLAN: >>>>>> >>>>>> ++ u32 vlan_entry_type = >>>>>> cpsw_ale_get_vlan_entry_type(ale_pos); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (vlan_entry_type == VLAN_INNER_ENTRY) >>>>>> >>>>>> ++ cpsw_ale_dump_inner_vlan_entry(i, ale_pos); >>>>>> >>>>>> ++ else if (vlan_entry_type == VLAN_OUTER_ENTRY) >>>>>> >>>>>> ++ cpsw_ale_dump_outer_vlan_entry(i, ale_pos); >>>>>> >>>>>> ++ else if (vlan_entry_type == VLAN_ETHERTYPE_ENTRY) >>>>>> >>>>>> ++ cpsw_ale_dump_ethertype_entry(i, ale_pos); >>>>>> >>>>>> ++ else if (vlan_entry_type == VLAN_IPV4_ENTRY) >>>>>> >>>>>> ++ cpsw_ale_dump_ipv4_entry(i, ale_pos); >>>>>> >>>>>> ++ else if (vlan_entry_type & VLAN_IPV6_ENTRY_MASK) >>>>>> >>>>>> ++ cpsw_ale_dump_ipv6_entry(i, ale_pos); >>>>>> >>>>>> ++ break; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ case ALE_ENTRY_VLAN_ADDR: >>>>>> >>>>>> ++ cpsw_ale_dump_vlan_addr(i, ale_pos); >>>>>> >>>>>> ++ break; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ default: >>>>>> >>>>>> ++ break; >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ ale_pos += ALE_ENTRY_WORDS; >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++} >>>>>> >>>>>> ++ >>>>>> >>>>>> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info >>>>>> __maybe_unused, >>>>>> >>>>>> ++ struct ethtool_regs *regs) >>>>>> >>>>>> ++{ >>>>>> >>>>>> ++ struct k3_cpsw_regdump_hdr *dump_hdr, *ale_hdr = NULL; >>>>>> >>>>>> ++ u32 *reg = (u32 *)regs->data, *ale_pos; >>>>>> >>>>>> ++ u32 mod_id; >>>>>> >>>>>> ++ int i, regdump_len = info->regdump_len; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "K3 CPSW dump version: %d, len: %d\n", >>>>>> >>>>>> ++ regs->version, info->regdump_len); >>>>>> >>>>>> ++ fprintf(stdout, "(Missing registers in memory space can be >>>>>> considered as zero valued)\n"); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ /* Line break before register dump */ >>>>>> >>>>>> ++ fprintf(stdout, >>>>>> "--------------------------------------------------------------------\n"); >>>>>> >>>>>> ++ i = 0; >>>>>> >>>>>> ++ do { >>>>>> >>>>>> ++ u32 *tmp, j; >>>>>> >>>>>> ++ u32 num_items; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ dump_hdr = (struct k3_cpsw_regdump_hdr *)reg; >>>>>> >>>>>> ++ mod_id = dump_hdr->module_id; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ num_items = dump_hdr->len / sizeof(u32); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE) >>>>>> >>>>>> ++ rtl_version = reg[3] & RTL_VERSION_MASK; >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { >>>>>> >>>>>> ++ ale_hdr = dump_hdr; >>>>>> >>>>>> ++ ale_pos = reg; >>>>>> >>>>>> ++ break; >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ fprintf(stdout, "%s regdump: number of Registers:(%d)\n", >>>>>> >>>>>> ++ mod_names[mod_id], num_items - 2); >>>>>> >>>>>> ++ tmp = reg; >>>>>> >>>>>> ++ /* Values are stored in pair as reg_offset-reg_val, >>>>>> hence parse the same way*/ >>>>>> >>>>>> ++ for (j = 2; j < num_items; j += 2) { >>>>>> >>>>>> ++ if (tmp[j + 1] != 0x0) >>>>>> >>>>>> ++ fprintf(stdout, "%08x:reg(%08X)\n", tmp[j], >>>>>> tmp[j + 1]); >>>>>> >>>>>> ++ } >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ reg += num_items; >>>>>> >>>>>> ++ i += dump_hdr->len; >>>>>> >>>>>> ++ } while (i < regdump_len); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ /* Adding a boundary in between Register dump and ALE table */ >>>>>> >>>>>> ++ fprintf(stdout, "--------------------------\n"); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ cpsw_dump_ale(ale_hdr, ale_pos); >>>>>> >>>>>> ++ >>>>>> >>>>>> ++ return 0; >>>>>> >>>>>> ++}; >>>>>> >>>>>> +diff --git a/ethtool.c b/ethtool.c >>>>>> >>>>>> +index 3ac15a7..a383eb6 100644 >>>>>> >>>>>> +--- a/ethtool.c >>>>>> >>>>>> ++++ b/ethtool.c >>>>>> >>>>>> +@@ -1162,6 +1162,7 @@ static const struct { >>>>>> >>>>>> + { "fsl_enetc", fsl_enetc_dump_regs }, >>>>>> >>>>>> + { "fsl_enetc_vf", fsl_enetc_dump_regs }, >>>>>> >>>>>> + { "hns3", hns3_dump_regs }, >>>>>> >>>>>> ++ { "am65-cpsw-nuss", am65_cpsw_dump_regs }, >>>>>> >>>>>> + }; >>>>>> >>>>>> + #endif >>>>>> >>>>>> + >>>>>> >>>>>> +diff --git a/internal.h b/internal.h >>>>>> >>>>>> +index 4b994f5..81212b4 100644 >>>>>> >>>>>> +--- a/internal.h >>>>>> >>>>>> ++++ b/internal.h >>>>>> >>>>>> +@@ -410,4 +410,7 @@ int cpsw_dump_regs(struct ethtool_drvinfo >>>>>> *info, struct ethtool_regs *regs); >>>>>> >>>>>> + /* Microchip Ethernet Controller */ >>>>>> >>>>>> + int lan743x_dump_regs(struct ethtool_drvinfo *info, struct >>>>>> ethtool_regs *regs); >>>>>> >>>>>> + >>>>>> >>>>>> ++/* TI K3 CPSW Ethernet Switch */ >>>>>> >>>>>> ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info, struct >>>>>> ethtool_regs *regs); >>>>>> >>>>>> ++ >>>>>> >>>>>> + #endif /* ETHTOOL_INTERNAL_H__ */ >>>>>> >>>>>> +-- >>>>>> >>>>>> +2.34.1 >>>>>> >>>>>> + >>>>>> >>>>>> diff --git >>>>>> a/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>>>> b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>>>> new file mode 100644 >>>>>> index 00000000..3b388151 >>>>>> --- /dev/null >>>>>> +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend >>>>>> @@ -0,0 +1,4 @@ >>>>>> +ETHTOOL_ARAGO = "" >>>>>> +ETHTOOL_ARAGO:arago = "ethtool-arago.inc" >>>>>> + >>>>>> +require ${ETHTOOL_ARAGO} >>>>>> -- >>>>>> 2.34.1 >>>> >>>> >>>> >>>> >>>> >> -- Ryan Eatmon reatmon@ti.com ----------------------------------------- Texas Instruments, Inc. - LCPD - MGTS
On Fri, Jul 11, 2025 at 01:10:58PM -0500, Andrew Davis wrote: > On 7/11/25 12:31 PM, Ryan Eatmon via lists.yoctoproject.org wrote: > > > > > >On 7/10/2025 9:35 PM, Aniket Limaye wrote: > >>Denys, Ryan, > >> > >>On 11/07/25 07:04, Aniket Limaye via lists.yoctoproject.org wrote: > >>> > >>> > >>>On 11/07/25 06:02, Denys Dmytriyenko wrote: > >>>>I wonder if the patch itself is malformed - specifically if it has windows > >>>>newlines that result in interlaced empty lines in mutt on Linux, as seen > >>>>below. While .inc and .bbappend seem fine. > >>>> > >>> > >>>Chintan, Yeah looks like the patchfile I added was not properly formatted. I will try resending this one quickly. > >>> > >> > >>Not sure what caused the weird encoding in the first place... > >> > >>Sent v2 here: https://lists.yoctoproject.org/g/meta-arago/message/16282 > > > >What's really odd is that applying the v1 patch resulted in a perfectly fine file in the repo. I applied this patch yesterday and the patch file looks fine. Or am I wrong. The issue is that this patch is already on next and is going through CICD promotion right now. If this is a problem we may need to submit a follow on patch to fix it. Can someone check the current file in the repo and verify? > > > > > > $ git checkout 83558083 > $ file meta-arago-distro/recipes-extended/ethtool/ethtool/0001-pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch > meta-arago-distro/recipes-extended/ethtool/ethtool/0001-pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch: unified diff output, ASCII text > > Looks fine to me, all those odd newlines must have been removed by > whatever tool you used to apply the email. Patchwork might have handled those. I see the issue locally in mutt and on the list, but not in patchwork. v1 with extra newlines: https://lists.yoctoproject.org/g/meta-arago/message/16277 v2 fixed: https://lists.yoctoproject.org/g/meta-arago/message/16282 patchwork for v1 that doesn't show extra newlines in the patch, but shows them in all comments: https://patchwork.yoctoproject.org/project/arago/patch/20250707090720.750031-1-a-limaye@ti.com/ > Andrew > > > > >> > >>>Thanks, > >>>Aniket > >>> > >>>> > >>>>On Mon, Jul 07, 2025 at 02:37:20PM +0530, Aniket Limaye via lists.yoctoproject.org wrote: > >>>>>Add support for TI K3 CPSW register and ALE table dump through the > >>>>>ethtool userspace utility. > >>>>> > >>>>>Signed-off-by: Aniket Limaye <a-limaye@ti.com> > >>>>>--- > >>>>> .../ethtool/ethtool-arago.inc | 8 + > >>>>> ...k3-cpsw-registers-and-ale-table-dump.patch | 574 ++++++++++++++++++ > >>>>> .../ethtool/ethtool_%.bbappend | 4 + > >>>>> 3 files changed, 586 insertions(+) > >>>>> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc > >>>>> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch > >>>>> create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend > >>>>> > >>>>>diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc > >>>>>new file mode 100644 > >>>>>index 00000000..5fd05a85 > >>>>>--- /dev/null > >>>>>+++ b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc > >>>>>@@ -0,0 +1,8 @@ > >>>>>+PR:append = ".arago0" > >>>>>+ > >>>>>+FILESEXTRAPATHS:prepend := "${THISDIR}/ethtool:" > >>>>>+ > >>>>>+SRC_URI:append = " \ > >>>>>+ file://pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch \ > >>>>>+ " > >>>>>+ > >>>>>diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch > >>>>>new file mode 100644 > >>>>>index 00000000..a14089b4 > >>>>>--- /dev/null > >>>>>+++ b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch > >>>>>@@ -0,0 +1,574 @@ > >>>>>+From: Chintan Vankar <c-vankar@ti.com> > >>>>> > >>>>>+Subject: [PATCH] pretty: Add support for TI K3 CPSW registers and ALE table dump > >>>>> > >>>>>+Date: Thu, 3 Jul 2025 12:02:46 +0530 > >>>>> > >>>>>+ > >>>>> > >>>>>+Add support to dump CPSW registers and ALE table for the CPSW instances on > >>>>> > >>>>>+K3 SoCs that are configured using the am65-cpsw-nuss.c device-driver in > >>>>> > >>>>>+Linux. > >>>>> > >>>>>+ > >>>>> > >>>>>+Upstream-Status: Submitted [https://lore.kernel.org/all/20250705134807.3514891-1-c-vankar@ti.com/] > >>>>> > >>>>>+Signed-off-by: Chintan Vankar <c-vankar@ti.com> > >>>>> > >>>>>+--- > >>>>> > >>>>>+ Makefile.am | 2 +- > >>>>> > >>>>>+ am65-cpsw-nuss.c | 510 +++++++++++++++++++++++++++++++++++++++++++++++ > >>>>> > >>>>>+ ethtool.c | 1 + > >>>>> > >>>>>+ internal.h | 3 + > >>>>> > >>>>>+ 4 files changed, 515 insertions(+), 1 deletion(-) > >>>>> > >>>>>+ create mode 100644 am65-cpsw-nuss.c > >>>>> > >>>>>+ > >>>>> > >>>>>+diff --git a/Makefile.am b/Makefile.am > >>>>> > >>>>>+index b9e06ad..fe6afcb 100644 > >>>>> > >>>>>+--- a/Makefile.am > >>>>> > >>>>>++++ b/Makefile.am > >>>>> > >>>>>+@@ -23,7 +23,7 @@ ethtool_SOURCES += \ > >>>>> > >>>>>+ smsc911x.c at76c50x-usb.c sfc.c stmmac.c \ > >>>>> > >>>>>+ sff-common.c sff-common.h sfpid.c sfpdiag.c \ > >>>>> > >>>>>+ ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c \ > >>>>> > >>>>>+- igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c > >>>>> > >>>>>++ igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c am65-cpsw-nuss.c > >>>>> > >>>>>+ endif > >>>>> > >>>>>+ > >>>>> > >>>>>+ if ENABLE_BASH_COMPLETION > >>>>> > >>>>>+diff --git a/am65-cpsw-nuss.c b/am65-cpsw-nuss.c > >>>>> > >>>>>+new file mode 100644 > >>>>> > >>>>>+index 0000000..de8e3e9 > >>>>> > >>>>>+--- /dev/null > >>>>> > >>>>>++++ b/am65-cpsw-nuss.c > >>>>> > >>>>>+@@ -0,0 +1,510 @@ > >>>>> > >>>>>++// SPDX-License-Identifier: GPL-2.0-only OR MIT > >>>>> > >>>>>++/* Code to dump registers and ALE table for the CPSW instances on K3 SoCs that are configured using > >>>>> > >>>>>++ * the am65-cpsw-nuss device-driver in Linux. > >>>>> > >>>>>++ * > >>>>> > >>>>>++ * Copyright (C) 2025 Texas Instruments > >>>>> > >>>>>++ * Author: Chintan Vankar <c-vankar@ti.com> > >>>>> > >>>>>++ */ > >>>>> > >>>>>++ > >>>>> > >>>>>++#include <stdio.h> > >>>>> > >>>>>++#include <string.h> > >>>>> > >>>>>++ > >>>>> > >>>>>++#include "internal.h" > >>>>> > >>>>>++ > >>>>> > >>>>>++#define ALE_ENTRY_BITS 74 > >>>>> > >>>>>++#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) > >>>>> > >>>>>++ > >>>>> > >>>>>++#define ALE_ENTRY_FREE 0x0 > >>>>> > >>>>>++#define ALE_ENTRY_ADDR 0x1 > >>>>> > >>>>>++#define ALE_ENTRY_VLAN 0x2 > >>>>> > >>>>>++#define ALE_ENTRY_VLAN_ADDR 0x3 > >>>>> > >>>>>++ > >>>>> > >>>>>++#define BIT(nr) (1 << (nr)) > >>>>> > >>>>>++#define BITMASK(bits) (BIT(bits) - 1) > >>>>> > >>>>>++ > >>>>> > >>>>>++/* ALE word specifiers */ > >>>>> > >>>>>++#define NUM_ALE_WORDS 2 > >>>>> > >>>>>++#define ALE_WORD_LEN 32 > >>>>> > >>>>>++ > >>>>> > >>>>>++/* MAC address specifiers */ > >>>>> > >>>>>++#define MAC_START_BIT 40 > >>>>> > >>>>>++#define MAC_OCTET_LEN 8 > >>>>> > >>>>>++#define NUM_MAC_OCTET 6 > >>>>> > >>>>>++ > >>>>> > >>>>>++/* RTL version specifiers */ > >>>>> > >>>>>++#define RTL_VERSION_MASK 0xF800 > >>>>> > >>>>>++#define CPSW2G_RTL_VERSION 0x3800 > >>>>> > >>>>>++#define CPSW3G_RTL_VERSION 0x0 > >>>>> > >>>>>++ > >>>>> > >>>>>++/* OUI address uses format xx:xx:xx, use OUI shift as 16 bits and MASK as 0xFF to parse the same*/ > >>>>> > >>>>>++#define OUI_ADDR_SHIFT 16 > >>>>> > >>>>>++#define OUI_ADDR_MASK 0xFF > >>>>> > >>>>>++ > >>>>> > >>>>>++/* VLAN entry specifiers */ > >>>>> > >>>>>++#define VLAN_INNER_ENTRY 0x0 > >>>>> > >>>>>++#define VLAN_OUTER_ENTRY 0x2 > >>>>> > >>>>>++#define VLAN_ETHERTYPE_ENTRY 0x4 > >>>>> > >>>>>++#define VLAN_IPV4_ENTRY 0x6 > >>>>> > >>>>>++#define VLAN_IPV6_ENTRY_MASK 0x1 > >>>>> > >>>>>++ > >>>>> > >>>>>++/* VLAN Inner/Outer table entry MASKs and SHIFTs*/ > >>>>> > >>>>>++#define NOLEARN_FLAG_SHIFT 2 > >>>>> > >>>>>++#define NOLEARN_FLAG_MASK 0x1FF > >>>>> > >>>>>++#define INGRESS_CHECK_SHIFT 1 > >>>>> > >>>>>++#define INGRESS_CHECK_MASK 0x1 > >>>>> > >>>>>++#define VLAN_ID_SHIFT 16 > >>>>> > >>>>>++#define VLAN_ID_MASK 0xFFF > >>>>> > >>>>>++#define NOFRAG_FLAG_SHIFT_2G 12 > >>>>> > >>>>>++#define NOFRAG_FLAG_MASK_2G 0x1 > >>>>> > >>>>>++#define NOFRAG_FLAG_SHIFT 15 > >>>>> > >>>>>++#define NOFRAG_FLAG_MASK 0x1 > >>>>> > >>>>>++#define REG_MASK_SHIFT 4 > >>>>> > >>>>>++#define REG_MASK_MASK 0x1FF > >>>>> > >>>>>++#define PKT_EGRESS_W1_MASK 0x1 > >>>>> > >>>>>++#define PKT_EGRESS_W1_OFFSET 512 > >>>>> > >>>>>++#define PKT_EGRESS_SHIFT 24 > >>>>> > >>>>>++#define PKT_EGRESS_MASK_2G 0x3 > >>>>> > >>>>>++#define PKT_EGRESS_MASK 0x1FF > >>>>> > >>>>>++#define UNREG_MASK_SHIFT_2G 20 > >>>>> > >>>>>++#define UNREG_MASK_MASK_2G 0x7 > >>>>> > >>>>>++#define UNREG_MASK_SHIFT 12 > >>>>> > >>>>>++#define UNREG_MASK_MASK 0x1FF > >>>>> > >>>>>++#define NXT_HDR_CTRL_SHIFT_2G 19 > >>>>> > >>>>>++#define NXT_HDR_CTRL_MASK_2G 0x1 > >>>>> > >>>>>++#define NXT_HDR_CTRL_SHIFT 23 > >>>>> > >>>>>++#define NXT_HDR_CTRL_MASK 0x1 > >>>>> > >>>>>++#define VLAN_MEMBER_LIST_MASK_2G 0x3 > >>>>> > >>>>>++#define VLAN_MEMBER_LIST_MASK 0x1FF > >>>>> > >>>>>++ > >>>>> > >>>>>++/* VLAN IPv4 entry MASKs and SHIFTs*/ > >>>>> > >>>>>++#define IPV4_ADDR_OCT1_SHIFT 24 > >>>>> > >>>>>++#define IPV4_ADDR_OCT2_SHIFT 16 > >>>>> > >>>>>++#define IPV4_ADDR_OCT3_SHIFT 8 > >>>>> > >>>>>++#define IPV4_ADDR_MASK 0xFF > >>>>> > >>>>>++ > >>>>> > >>>>>++/* VLAN IPv6 entry MASKs and SHIFTs*/ > >>>>> > >>>>>++#define IPV6_HIGH_ENTRY_FLAG 0x40 > >>>>> > >>>>>++#define IPV6_IGNMCBITS_MASK 0xFF > >>>>> > >>>>>++#define IPV6_HADDR_W1_SHIFT 12 > >>>>> > >>>>>++#define IPV6_HADDR_W1_MASK_1 0xFFFF > >>>>> > >>>>>++#define IPV6_HADDR_W1_MASK_2 0xFFF > >>>>> > >>>>>++#define IPV6_HADDR_W0_SHIFT_1 28 > >>>>> > >>>>>++#define IPV6_HADDR_W0_MASK_1 0xF > >>>>> > >>>>>++#define IPV6_HADDR_W0_SHIFT_2 12 > >>>>> > >>>>>++#define IPV6_HADDR_W0_MASK_2 0xFFFF > >>>>> > >>>>>++#define IPV6_LADDR_W2_SHIFT 4 > >>>>> > >>>>>++#define IPV6_LADDR_W2_MAKS 0xF > >>>>> > >>>>>++#define IPV6_LADDR_W1_SHIFT 16 > >>>>> > >>>>>++#define IPV6_LADDR_W1_MASK_1 0xFFF > >>>>> > >>>>>++#define IPV6_LADDR_W1_MASK 0xFFFF > >>>>> > >>>>>++#define IPV6_LADDR_W0_SHIFT 16 > >>>>> > >>>>>++#define IPV6_LADDR_W0_MASK 0xFFFF > >>>>> > >>>>>++ > >>>>> > >>>>>++/** > >>>>> > >>>>>++ * Since there are different instances of CPSW (namely cpsw2g, cpsw3g, cpsw5g and cpsw9g) > >>>>> > >>>>>++ * some register offsets differ to get some parameters for ALE table, parse rtl_version > >>>>> > >>>>>++ * from ALE_MOD_VER register to determine which instance is being used. > >>>>> > >>>>>++ */ > >>>>> > >>>>>++u32 rtl_version; > >>>>> > >>>>>++ > >>>>> > >>>>>++static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ int idx; > >>>>> > >>>>>++ > >>>>> > >>>>>++ idx = start / ALE_WORD_LEN; > >>>>> > >>>>>++ start -= idx * ALE_WORD_LEN; > >>>>> > >>>>>++ > >>>>> > >>>>>++ /** > >>>>> > >>>>>++ * ALE words are stored in order word2, word1 and word0, flip the word to parse in numeric > >>>>> > >>>>>++ * order > >>>>> > >>>>>++ */ > >>>>> > >>>>>++ idx = NUM_ALE_WORDS - idx; /* flip */ > >>>>> > >>>>>++ return (ale_entry[idx] >> start) & BITMASK(bits); > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++#define DEFINE_ALE_FIELD(name, start, bits) \ > >>>>> > >>>>>++static inline int cpsw_ale_get_##name(u32 *ale_entry) \ > >>>>> > >>>>>++{ \ > >>>>> > >>>>>++ return cpsw_ale_get_field(ale_entry, start, bits); \ > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++DEFINE_ALE_FIELD(entry_type, 60, 2) > >>>>> > >>>>>++DEFINE_ALE_FIELD(vlan_id, 48, 12) > >>>>> > >>>>>++DEFINE_ALE_FIELD(mcast_state, 62, 2) > >>>>> > >>>>>++DEFINE_ALE_FIELD(port_mask, 66, 9) > >>>>> > >>>>>++DEFINE_ALE_FIELD(super, 65, 1) > >>>>> > >>>>>++DEFINE_ALE_FIELD(agable, 62, 1) > >>>>> > >>>>>++DEFINE_ALE_FIELD(touched, 63, 1) > >>>>> > >>>>>++DEFINE_ALE_FIELD(ucast_type, 62, 2) > >>>>> > >>>>>++DEFINE_ALE_FIELD(port_num, 66, 4) > >>>>> > >>>>>++DEFINE_ALE_FIELD(port_num_2g, 66, 1) > >>>>> > >>>>>++DEFINE_ALE_FIELD(port_num_3g, 66, 2) > >>>>> > >>>>>++DEFINE_ALE_FIELD(blocked, 65, 1) > >>>>> > >>>>>++DEFINE_ALE_FIELD(secure, 64, 1) > >>>>> > >>>>>++DEFINE_ALE_FIELD(oui_entry, 62, 2) > >>>>> > >>>>>++DEFINE_ALE_FIELD(oui_addr, 4, 24) > >>>>> > >>>>>++DEFINE_ALE_FIELD(mcast, 40, 1) > >>>>> > >>>>>++DEFINE_ALE_FIELD(vlan_entry_type, 62, 3) > >>>>> > >>>>>++DEFINE_ALE_FIELD(ethertype, 0, 16) > >>>>> > >>>>>++DEFINE_ALE_FIELD(ipv4_addr, 0, 32) > >>>>> > >>>>>++DEFINE_ALE_FIELD(ingress_bits, 65, 5) > >>>>> > >>>>>++DEFINE_ALE_FIELD(ipv6_addr_low, 0, 60) > >>>>> > >>>>>++DEFINE_ALE_FIELD(ipv6_addr_mid, 63, 8) > >>>>> > >>>>>++DEFINE_ALE_FIELD(ipv6_addr_high, 0, 60) > >>>>> > >>>>>++DEFINE_ALE_FIELD(entry_word0, 0, 32) > >>>>> > >>>>>++DEFINE_ALE_FIELD(entry_word1, 32, 32) > >>>>> > >>>>>++DEFINE_ALE_FIELD(entry_word2, 64, 12) > >>>>> > >>>>>++ > >>>>> > >>>>>++static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ int i; > >>>>> > >>>>>++ > >>>>> > >>>>>++ for (i = 0; i < NUM_MAC_OCTET; i++) > >>>>> > >>>>>++ addr[i] = cpsw_ale_get_field(ale_entry, MAC_START_BIT - MAC_OCTET_LEN * i, > >>>>> > >>>>>++ MAC_OCTET_LEN); > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++struct k3_cpsw_regdump_hdr { > >>>>> > >>>>>++ u32 module_id; > >>>>> > >>>>>++ u32 len; > >>>>> > >>>>>++}; > >>>>> > >>>>>++ > >>>>> > >>>>>++enum { > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_NUSS = 1, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_MDIO = 3, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_CPSW = 4, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_CPSW_P0 = 5, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_CPSW_PN = 6, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_CPSW_ALE = 8, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, > >>>>> > >>>>>++ K3_CPSW_REGDUMP_MOD_LAST, > >>>>> > >>>>>++}; > >>>>> > >>>>>++ > >>>>> > >>>>>++static const char *mod_names[K3_CPSW_REGDUMP_MOD_LAST] = { > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_NUSS] = "cpsw-nuss", > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_RGMII_STATUS] = "cpsw-nuss-rgmii-status", > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_MDIO] = "cpsw-nuss-mdio", > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_CPSW] = "cpsw-nu", > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_CPSW_P0] = "cpsw-nu-p0", > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_CPSW_PN] = "cpsw-nu-pn", > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_CPSW_CPTS] = "cpsw-nu-cpts", > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE] = "cpsw-nu-ale", > >>>>> > >>>>>++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL] = "cpsw-nu-ale-tbl", > >>>>> > >>>>>++}; > >>>>> > >>>>>++ > >>>>> > >>>>>++static void cpsw_ale_dump_oui_entry(int index, u32 *ale_entry) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ u32 oui_addr; > >>>>> > >>>>>++ > >>>>> > >>>>>++ oui_addr = cpsw_ale_get_oui_addr(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: OUI Unicast\n, \tOUI = %02x:%02x:%02x\n", > >>>>> > >>>>>++ index, (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, > >>>>> > >>>>>++ (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, oui_addr & OUI_ADDR_MASK); > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++static void cpsw_ale_dump_addr(int index, u32 *ale_entry) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ u8 addr[NUM_MAC_OCTET]; > >>>>> > >>>>>++ > >>>>> > >>>>>++ cpsw_ale_get_addr(ale_entry, addr); > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (cpsw_ale_get_mcast(ale_entry)) { > >>>>> > >>>>>++ static const char * const str_mcast_state[] = {"Forwarding", > >>>>> > >>>>>++ "Blocking/Forwarding/Learning", > >>>>> > >>>>>++ "Learning/Forwarding", > >>>>> > >>>>>++ "Forwarding"}; > >>>>> > >>>>>++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); > >>>>> > >>>>>++ u8 state = cpsw_ale_get_mcast_state(ale_entry); > >>>>> > >>>>>++ u8 super = cpsw_ale_get_super(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: Multicast\n \tAddress = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_State = %s, %sSuper, port_mask = 0x%x\n", > >>>>> > >>>>>++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], > >>>>> > >>>>>++ str_mcast_state[state], super ? "" : "No ", port_mask); > >>>>> > >>>>>++ } else { > >>>>> > >>>>>++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", > >>>>> > >>>>>++ "Touched"}; > >>>>> > >>>>>++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); > >>>>> > >>>>>++ u8 port_num = cpsw_ale_get_port_num(ale_entry); > >>>>> > >>>>>++ u8 blocked = cpsw_ale_get_blocked(ale_entry); > >>>>> > >>>>>++ u8 touched = cpsw_ale_get_touched(ale_entry); > >>>>> > >>>>>++ u8 secure = cpsw_ale_get_secure(ale_entry); > >>>>> > >>>>>++ u8 agable = cpsw_ale_get_agable(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: Unicast\n \tUpdated Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast Type = %s, Port_num = 0x%x, Secure: %d, Blocked: %d, Touch = %d, Agable = %d\n", > >>>>> > >>>>>++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], > >>>>> > >>>>>++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); > >>>>> > >>>>>++ } > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++static void cpsw_ale_dump_inner_vlan_entry(int index, u32 *ale_entry) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); > >>>>> > >>>>>++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); > >>>>> > >>>>>++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: Inner VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", > >>>>> > >>>>>++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, > >>>>> > >>>>>++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (rtl_version == CPSW2G_RTL_VERSION) { > >>>>> > >>>>>++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", > >>>>> > >>>>>++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, > >>>>> > >>>>>++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, > >>>>> > >>>>>++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", > >>>>> > >>>>>++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, > >>>>> > >>>>>++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, > >>>>> > >>>>>++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, > >>>>> > >>>>>++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); > >>>>> > >>>>>++ } else { > >>>>> > >>>>>++ fprintf(stdout, "\tVLAN ID = %d, Registered Mask = 0x%x, No Frag = %d\n", > >>>>> > >>>>>++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, > >>>>> > >>>>>++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK, > >>>>> > >>>>>++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x, Members = 0x%x\n", > >>>>> > >>>>>++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + > >>>>> > >>>>>++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), > >>>>> > >>>>>++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, > >>>>> > >>>>>++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, > >>>>> > >>>>>++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); > >>>>> > >>>>>++ } > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++static void cpsw_ale_dump_outer_vlan_entry(int index, u32 *ale_entry) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); > >>>>> > >>>>>++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); > >>>>> > >>>>>++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: Outer VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", > >>>>> > >>>>>++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, > >>>>> > >>>>>++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (rtl_version == CPSW2G_RTL_VERSION) { > >>>>> > >>>>>++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", > >>>>> > >>>>>++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, > >>>>> > >>>>>++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, > >>>>> > >>>>>++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", > >>>>> > >>>>>++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, > >>>>> > >>>>>++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, > >>>>> > >>>>>++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, > >>>>> > >>>>>++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); > >>>>> > >>>>>++ } else { > >>>>> > >>>>>++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", > >>>>> > >>>>>++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, > >>>>> > >>>>>++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK, > >>>>> > >>>>>++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x Members = 0x%x\n", > >>>>> > >>>>>++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + > >>>>> > >>>>>++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), > >>>>> > >>>>>++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, > >>>>> > >>>>>++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, > >>>>> > >>>>>++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); > >>>>> > >>>>>++ } > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++static void cpsw_ale_dump_ethertype_entry(int index, u32 *ale_entry) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ u16 ethertype = cpsw_ale_get_ethertype(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: VLAN Ethertype\n \tEthertype = 0x%x\n", index, ethertype); > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++static void cpsw_ale_dump_ipv4_entry(int index, u32 *ale_entry) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ u8 ingress_bits = cpsw_ale_get_ingress_bits(ale_entry); > >>>>> > >>>>>++ u32 ipv4_addr = cpsw_ale_get_ipv4_addr(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: VLAN IPv4\n \tIngress Bits: 0x%x IPv4 Address = %u.%u.%u.%u\n", > >>>>> > >>>>>++ index, ingress_bits, ipv4_addr >> IPV4_ADDR_OCT1_SHIFT & IPV4_ADDR_MASK, > >>>>> > >>>>>++ ipv4_addr >> IPV4_ADDR_OCT2_SHIFT & IPV4_ADDR_MASK, > >>>>> > >>>>>++ ipv4_addr >> IPV4_ADDR_OCT3_SHIFT & IPV4_ADDR_MASK, ipv4_addr & IPV4_ADDR_MASK); > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++static void cpsw_ale_dump_ipv6_entry(int index, u32 *ale_entry) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); > >>>>> > >>>>>++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); > >>>>> > >>>>>++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (index & IPV6_HIGH_ENTRY_FLAG) { > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: VLAN IPv6 Higher Entry (Lower Bit entry at %04u)\n \tIgnored Multicast bits: 0x%x, IPv6 Address (Bits [127:68]) = %04x:%03x%01x:%04x:%03x\n", > >>>>> > >>>>>++ index, (index & (~IPV6_HIGH_ENTRY_FLAG)), > >>>>> > >>>>>++ vlan_entry_word2 & IPV6_IGNMCBITS_MASK, > >>>>> > >>>>>++ (vlan_entry_word1 >> IPV6_HADDR_W1_SHIFT) & IPV6_HADDR_W1_MASK_1, > >>>>> > >>>>>++ vlan_entry_word1 & IPV6_HADDR_W1_MASK_2, > >>>>> > >>>>>++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_1) & IPV6_HADDR_W0_MASK_1, > >>>>> > >>>>>++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_2) & IPV6_HADDR_W0_MASK_2, > >>>>> > >>>>>++ vlan_entry_word0 & IPV6_HADDR_W0_MASK_2); > >>>>> > >>>>>++ } else { > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: VLAN IPv6 Lower Entry (Higher Bit entry at %04u)\n \tIPv6 Address (Bits [127:68]) = %01x:%01x%03x:%04x:%04x:%04x\n", > >>>>> > >>>>>++ index, (index | IPV6_HIGH_ENTRY_FLAG), > >>>>> > >>>>>++ (vlan_entry_word2 >> IPV6_LADDR_W2_SHIFT) & IPV6_LADDR_W2_MAKS, > >>>>> > >>>>>++ vlan_entry_word2 & IPV6_LADDR_W2_MAKS, > >>>>> > >>>>>++ (vlan_entry_word1 >> IPV6_LADDR_W1_SHIFT) & IPV6_LADDR_W1_MASK_1, > >>>>> > >>>>>++ vlan_entry_word1 & IPV6_LADDR_W1_MASK, > >>>>> > >>>>>++ (vlan_entry_word0 >> IPV6_LADDR_W0_SHIFT) & IPV6_LADDR_W0_MASK, > >>>>> > >>>>>++ vlan_entry_word0 & IPV6_LADDR_W0_MASK); > >>>>> > >>>>>++ } > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ u8 addr[NUM_MAC_OCTET]; > >>>>> > >>>>>++ int vlan = cpsw_ale_get_vlan_id(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ cpsw_ale_get_addr(ale_entry, addr); > >>>>> > >>>>>++ if (cpsw_ale_get_mcast(ale_entry)) { > >>>>> > >>>>>++ static const char * const str_mcast_state[] = {"Forwarding", > >>>>> > >>>>>++ "Blocking/Forwarding/Learning", > >>>>> > >>>>>++ "Learning/Forwarding", > >>>>> > >>>>>++ "Forwarding"}; > >>>>> > >>>>>++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); > >>>>> > >>>>>++ u8 state = cpsw_ale_get_mcast_state(ale_entry); > >>>>> > >>>>>++ u8 super = cpsw_ale_get_super(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: Multicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_state = %s, %s Super, port_mask = 0x%x\n", > >>>>> > >>>>>++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], > >>>>> > >>>>>++ str_mcast_state[state], super ? "" : "No ", port_mask); > >>>>> > >>>>>++ } else { > >>>>> > >>>>>++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", > >>>>> > >>>>>++ "Touched"}; > >>>>> > >>>>>++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); > >>>>> > >>>>>++ u8 blocked = cpsw_ale_get_blocked(ale_entry); > >>>>> > >>>>>++ u8 touched = cpsw_ale_get_touched(ale_entry); > >>>>> > >>>>>++ u8 secure = cpsw_ale_get_secure(ale_entry); > >>>>> > >>>>>++ u8 agable = cpsw_ale_get_agable(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ int port_num; > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (rtl_version == CPSW2G_RTL_VERSION) > >>>>> > >>>>>++ port_num = cpsw_ale_get_port_num_2g(ale_entry); > >>>>> > >>>>>++ else if (rtl_version == CPSW3G_RTL_VERSION) > >>>>> > >>>>>++ port_num = cpsw_ale_get_port_num_3g(ale_entry); > >>>>> > >>>>>++ else > >>>>> > >>>>>++ port_num = cpsw_ale_get_port_num(ale_entry); > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%d: Type: Unicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast_type = %s, port_num = 0x%x, Secure = %d, Blocked = %d, Touch = %d, Agable = %d\n", > >>>>> > >>>>>++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], > >>>>> > >>>>>++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); > >>>>> > >>>>>++ } > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++void cpsw_dump_ale(struct k3_cpsw_regdump_hdr *ale_hdr, u32 *ale_pos) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ int i, ale_entries; > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (!ale_hdr) > >>>>> > >>>>>++ return; > >>>>> > >>>>>++ > >>>>> > >>>>>++ ale_entries = (ale_hdr->len - sizeof(struct k3_cpsw_regdump_hdr)) / > >>>>> > >>>>>++ ALE_ENTRY_WORDS / sizeof(u32); > >>>>> > >>>>>++ > >>>>> > >>>>>++ printf("Number of ALE entries: %d\n", ale_entries); > >>>>> > >>>>>++ ale_pos += 2; > >>>>> > >>>>>++ for (i = 0; i < ale_entries; i++) { > >>>>> > >>>>>++ int type; > >>>>> > >>>>>++ > >>>>> > >>>>>++ type = cpsw_ale_get_entry_type(ale_pos); > >>>>> > >>>>>++ > >>>>> > >>>>>++ switch (type) { > >>>>> > >>>>>++ case ALE_ENTRY_FREE: > >>>>> > >>>>>++ break; > >>>>> > >>>>>++ > >>>>> > >>>>>++ case ALE_ENTRY_ADDR: > >>>>> > >>>>>++ u32 oui_entry = cpsw_ale_get_oui_addr(ale_pos); > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (oui_entry == 0x2) > >>>>> > >>>>>++ cpsw_ale_dump_oui_entry(i, ale_pos); > >>>>> > >>>>>++ else > >>>>> > >>>>>++ cpsw_ale_dump_addr(i, ale_pos); > >>>>> > >>>>>++ break; > >>>>> > >>>>>++ > >>>>> > >>>>>++ case ALE_ENTRY_VLAN: > >>>>> > >>>>>++ u32 vlan_entry_type = cpsw_ale_get_vlan_entry_type(ale_pos); > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (vlan_entry_type == VLAN_INNER_ENTRY) > >>>>> > >>>>>++ cpsw_ale_dump_inner_vlan_entry(i, ale_pos); > >>>>> > >>>>>++ else if (vlan_entry_type == VLAN_OUTER_ENTRY) > >>>>> > >>>>>++ cpsw_ale_dump_outer_vlan_entry(i, ale_pos); > >>>>> > >>>>>++ else if (vlan_entry_type == VLAN_ETHERTYPE_ENTRY) > >>>>> > >>>>>++ cpsw_ale_dump_ethertype_entry(i, ale_pos); > >>>>> > >>>>>++ else if (vlan_entry_type == VLAN_IPV4_ENTRY) > >>>>> > >>>>>++ cpsw_ale_dump_ipv4_entry(i, ale_pos); > >>>>> > >>>>>++ else if (vlan_entry_type & VLAN_IPV6_ENTRY_MASK) > >>>>> > >>>>>++ cpsw_ale_dump_ipv6_entry(i, ale_pos); > >>>>> > >>>>>++ break; > >>>>> > >>>>>++ > >>>>> > >>>>>++ case ALE_ENTRY_VLAN_ADDR: > >>>>> > >>>>>++ cpsw_ale_dump_vlan_addr(i, ale_pos); > >>>>> > >>>>>++ break; > >>>>> > >>>>>++ > >>>>> > >>>>>++ default: > >>>>> > >>>>>++ break; > >>>>> > >>>>>++ } > >>>>> > >>>>>++ > >>>>> > >>>>>++ ale_pos += ALE_ENTRY_WORDS; > >>>>> > >>>>>++ } > >>>>> > >>>>>++} > >>>>> > >>>>>++ > >>>>> > >>>>>++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused, > >>>>> > >>>>>++ struct ethtool_regs *regs) > >>>>> > >>>>>++{ > >>>>> > >>>>>++ struct k3_cpsw_regdump_hdr *dump_hdr, *ale_hdr = NULL; > >>>>> > >>>>>++ u32 *reg = (u32 *)regs->data, *ale_pos; > >>>>> > >>>>>++ u32 mod_id; > >>>>> > >>>>>++ int i, regdump_len = info->regdump_len; > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "K3 CPSW dump version: %d, len: %d\n", > >>>>> > >>>>>++ regs->version, info->regdump_len); > >>>>> > >>>>>++ fprintf(stdout, "(Missing registers in memory space can be considered as zero valued)\n"); > >>>>> > >>>>>++ > >>>>> > >>>>>++ /* Line break before register dump */ > >>>>> > >>>>>++ fprintf(stdout, "--------------------------------------------------------------------\n"); > >>>>> > >>>>>++ i = 0; > >>>>> > >>>>>++ do { > >>>>> > >>>>>++ u32 *tmp, j; > >>>>> > >>>>>++ u32 num_items; > >>>>> > >>>>>++ > >>>>> > >>>>>++ dump_hdr = (struct k3_cpsw_regdump_hdr *)reg; > >>>>> > >>>>>++ mod_id = dump_hdr->module_id; > >>>>> > >>>>>++ > >>>>> > >>>>>++ num_items = dump_hdr->len / sizeof(u32); > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE) > >>>>> > >>>>>++ rtl_version = reg[3] & RTL_VERSION_MASK; > >>>>> > >>>>>++ > >>>>> > >>>>>++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { > >>>>> > >>>>>++ ale_hdr = dump_hdr; > >>>>> > >>>>>++ ale_pos = reg; > >>>>> > >>>>>++ break; > >>>>> > >>>>>++ } > >>>>> > >>>>>++ > >>>>> > >>>>>++ fprintf(stdout, "%s regdump: number of Registers:(%d)\n", > >>>>> > >>>>>++ mod_names[mod_id], num_items - 2); > >>>>> > >>>>>++ tmp = reg; > >>>>> > >>>>>++ /* Values are stored in pair as reg_offset-reg_val, hence parse the same way*/ > >>>>> > >>>>>++ for (j = 2; j < num_items; j += 2) { > >>>>> > >>>>>++ if (tmp[j + 1] != 0x0) > >>>>> > >>>>>++ fprintf(stdout, "%08x:reg(%08X)\n", tmp[j], tmp[j + 1]); > >>>>> > >>>>>++ } > >>>>> > >>>>>++ > >>>>> > >>>>>++ reg += num_items; > >>>>> > >>>>>++ i += dump_hdr->len; > >>>>> > >>>>>++ } while (i < regdump_len); > >>>>> > >>>>>++ > >>>>> > >>>>>++ /* Adding a boundary in between Register dump and ALE table */ > >>>>> > >>>>>++ fprintf(stdout, "--------------------------\n"); > >>>>> > >>>>>++ > >>>>> > >>>>>++ cpsw_dump_ale(ale_hdr, ale_pos); > >>>>> > >>>>>++ > >>>>> > >>>>>++ return 0; > >>>>> > >>>>>++}; > >>>>> > >>>>>+diff --git a/ethtool.c b/ethtool.c > >>>>> > >>>>>+index 3ac15a7..a383eb6 100644 > >>>>> > >>>>>+--- a/ethtool.c > >>>>> > >>>>>++++ b/ethtool.c > >>>>> > >>>>>+@@ -1162,6 +1162,7 @@ static const struct { > >>>>> > >>>>>+ { "fsl_enetc", fsl_enetc_dump_regs }, > >>>>> > >>>>>+ { "fsl_enetc_vf", fsl_enetc_dump_regs }, > >>>>> > >>>>>+ { "hns3", hns3_dump_regs }, > >>>>> > >>>>>++ { "am65-cpsw-nuss", am65_cpsw_dump_regs }, > >>>>> > >>>>>+ }; > >>>>> > >>>>>+ #endif > >>>>> > >>>>>+ > >>>>> > >>>>>+diff --git a/internal.h b/internal.h > >>>>> > >>>>>+index 4b994f5..81212b4 100644 > >>>>> > >>>>>+--- a/internal.h > >>>>> > >>>>>++++ b/internal.h > >>>>> > >>>>>+@@ -410,4 +410,7 @@ int cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); > >>>>> > >>>>>+ /* Microchip Ethernet Controller */ > >>>>> > >>>>>+ int lan743x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); > >>>>> > >>>>>+ > >>>>> > >>>>>++/* TI K3 CPSW Ethernet Switch */ > >>>>> > >>>>>++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); > >>>>> > >>>>>++ > >>>>> > >>>>>+ #endif /* ETHTOOL_INTERNAL_H__ */ > >>>>> > >>>>>+-- > >>>>> > >>>>>+2.34.1 > >>>>> > >>>>>+ > >>>>> > >>>>>diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend > >>>>>new file mode 100644 > >>>>>index 00000000..3b388151 > >>>>>--- /dev/null > >>>>>+++ b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend > >>>>>@@ -0,0 +1,4 @@ > >>>>>+ETHTOOL_ARAGO = "" > >>>>>+ETHTOOL_ARAGO:arago = "ethtool-arago.inc" > >>>>>+ > >>>>>+require ${ETHTOOL_ARAGO} > >>>>>-- > >>>>>2.34.1 > >>> > >>> > >>> > >>> > >>> > >
diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc new file mode 100644 index 00000000..5fd05a85 --- /dev/null +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc @@ -0,0 +1,8 @@ +PR:append = ".arago0" + +FILESEXTRAPATHS:prepend := "${THISDIR}/ethtool:" + +SRC_URI:append = " \ + file://pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch \ + " + diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch new file mode 100644 index 00000000..a14089b4 --- /dev/null +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch @@ -0,0 +1,574 @@ +From: Chintan Vankar <c-vankar@ti.com> +Subject: [PATCH] pretty: Add support for TI K3 CPSW registers and ALE table dump +Date: Thu, 3 Jul 2025 12:02:46 +0530 + +Add support to dump CPSW registers and ALE table for the CPSW instances on +K3 SoCs that are configured using the am65-cpsw-nuss.c device-driver in +Linux. + +Upstream-Status: Submitted [https://lore.kernel.org/all/20250705134807.3514891-1-c-vankar@ti.com/] +Signed-off-by: Chintan Vankar <c-vankar@ti.com> +--- + Makefile.am | 2 +- + am65-cpsw-nuss.c | 510 +++++++++++++++++++++++++++++++++++++++++++++++ + ethtool.c | 1 + + internal.h | 3 + + 4 files changed, 515 insertions(+), 1 deletion(-) + create mode 100644 am65-cpsw-nuss.c + +diff --git a/Makefile.am b/Makefile.am +index b9e06ad..fe6afcb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -23,7 +23,7 @@ ethtool_SOURCES += \ + smsc911x.c at76c50x-usb.c sfc.c stmmac.c \ + sff-common.c sff-common.h sfpid.c sfpdiag.c \ + ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c \ +- igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c ++ igc.c cmis.c cmis.h bnxt.c cpsw.c lan743x.c hns3.c am65-cpsw-nuss.c + endif + + if ENABLE_BASH_COMPLETION +diff --git a/am65-cpsw-nuss.c b/am65-cpsw-nuss.c +new file mode 100644 +index 0000000..de8e3e9 +--- /dev/null ++++ b/am65-cpsw-nuss.c +@@ -0,0 +1,510 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* Code to dump registers and ALE table for the CPSW instances on K3 SoCs that are configured using ++ * the am65-cpsw-nuss device-driver in Linux. ++ * ++ * Copyright (C) 2025 Texas Instruments ++ * Author: Chintan Vankar <c-vankar@ti.com> ++ */ ++ ++#include <stdio.h> ++#include <string.h> ++ ++#include "internal.h" ++ ++#define ALE_ENTRY_BITS 74 ++#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) ++ ++#define ALE_ENTRY_FREE 0x0 ++#define ALE_ENTRY_ADDR 0x1 ++#define ALE_ENTRY_VLAN 0x2 ++#define ALE_ENTRY_VLAN_ADDR 0x3 ++ ++#define BIT(nr) (1 << (nr)) ++#define BITMASK(bits) (BIT(bits) - 1) ++ ++/* ALE word specifiers */ ++#define NUM_ALE_WORDS 2 ++#define ALE_WORD_LEN 32 ++ ++/* MAC address specifiers */ ++#define MAC_START_BIT 40 ++#define MAC_OCTET_LEN 8 ++#define NUM_MAC_OCTET 6 ++ ++/* RTL version specifiers */ ++#define RTL_VERSION_MASK 0xF800 ++#define CPSW2G_RTL_VERSION 0x3800 ++#define CPSW3G_RTL_VERSION 0x0 ++ ++/* OUI address uses format xx:xx:xx, use OUI shift as 16 bits and MASK as 0xFF to parse the same*/ ++#define OUI_ADDR_SHIFT 16 ++#define OUI_ADDR_MASK 0xFF ++ ++/* VLAN entry specifiers */ ++#define VLAN_INNER_ENTRY 0x0 ++#define VLAN_OUTER_ENTRY 0x2 ++#define VLAN_ETHERTYPE_ENTRY 0x4 ++#define VLAN_IPV4_ENTRY 0x6 ++#define VLAN_IPV6_ENTRY_MASK 0x1 ++ ++/* VLAN Inner/Outer table entry MASKs and SHIFTs*/ ++#define NOLEARN_FLAG_SHIFT 2 ++#define NOLEARN_FLAG_MASK 0x1FF ++#define INGRESS_CHECK_SHIFT 1 ++#define INGRESS_CHECK_MASK 0x1 ++#define VLAN_ID_SHIFT 16 ++#define VLAN_ID_MASK 0xFFF ++#define NOFRAG_FLAG_SHIFT_2G 12 ++#define NOFRAG_FLAG_MASK_2G 0x1 ++#define NOFRAG_FLAG_SHIFT 15 ++#define NOFRAG_FLAG_MASK 0x1 ++#define REG_MASK_SHIFT 4 ++#define REG_MASK_MASK 0x1FF ++#define PKT_EGRESS_W1_MASK 0x1 ++#define PKT_EGRESS_W1_OFFSET 512 ++#define PKT_EGRESS_SHIFT 24 ++#define PKT_EGRESS_MASK_2G 0x3 ++#define PKT_EGRESS_MASK 0x1FF ++#define UNREG_MASK_SHIFT_2G 20 ++#define UNREG_MASK_MASK_2G 0x7 ++#define UNREG_MASK_SHIFT 12 ++#define UNREG_MASK_MASK 0x1FF ++#define NXT_HDR_CTRL_SHIFT_2G 19 ++#define NXT_HDR_CTRL_MASK_2G 0x1 ++#define NXT_HDR_CTRL_SHIFT 23 ++#define NXT_HDR_CTRL_MASK 0x1 ++#define VLAN_MEMBER_LIST_MASK_2G 0x3 ++#define VLAN_MEMBER_LIST_MASK 0x1FF ++ ++/* VLAN IPv4 entry MASKs and SHIFTs*/ ++#define IPV4_ADDR_OCT1_SHIFT 24 ++#define IPV4_ADDR_OCT2_SHIFT 16 ++#define IPV4_ADDR_OCT3_SHIFT 8 ++#define IPV4_ADDR_MASK 0xFF ++ ++/* VLAN IPv6 entry MASKs and SHIFTs*/ ++#define IPV6_HIGH_ENTRY_FLAG 0x40 ++#define IPV6_IGNMCBITS_MASK 0xFF ++#define IPV6_HADDR_W1_SHIFT 12 ++#define IPV6_HADDR_W1_MASK_1 0xFFFF ++#define IPV6_HADDR_W1_MASK_2 0xFFF ++#define IPV6_HADDR_W0_SHIFT_1 28 ++#define IPV6_HADDR_W0_MASK_1 0xF ++#define IPV6_HADDR_W0_SHIFT_2 12 ++#define IPV6_HADDR_W0_MASK_2 0xFFFF ++#define IPV6_LADDR_W2_SHIFT 4 ++#define IPV6_LADDR_W2_MAKS 0xF ++#define IPV6_LADDR_W1_SHIFT 16 ++#define IPV6_LADDR_W1_MASK_1 0xFFF ++#define IPV6_LADDR_W1_MASK 0xFFFF ++#define IPV6_LADDR_W0_SHIFT 16 ++#define IPV6_LADDR_W0_MASK 0xFFFF ++ ++/** ++ * Since there are different instances of CPSW (namely cpsw2g, cpsw3g, cpsw5g and cpsw9g) ++ * some register offsets differ to get some parameters for ALE table, parse rtl_version ++ * from ALE_MOD_VER register to determine which instance is being used. ++ */ ++u32 rtl_version; ++ ++static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) ++{ ++ int idx; ++ ++ idx = start / ALE_WORD_LEN; ++ start -= idx * ALE_WORD_LEN; ++ ++ /** ++ * ALE words are stored in order word2, word1 and word0, flip the word to parse in numeric ++ * order ++ */ ++ idx = NUM_ALE_WORDS - idx; /* flip */ ++ return (ale_entry[idx] >> start) & BITMASK(bits); ++} ++ ++#define DEFINE_ALE_FIELD(name, start, bits) \ ++static inline int cpsw_ale_get_##name(u32 *ale_entry) \ ++{ \ ++ return cpsw_ale_get_field(ale_entry, start, bits); \ ++} ++ ++DEFINE_ALE_FIELD(entry_type, 60, 2) ++DEFINE_ALE_FIELD(vlan_id, 48, 12) ++DEFINE_ALE_FIELD(mcast_state, 62, 2) ++DEFINE_ALE_FIELD(port_mask, 66, 9) ++DEFINE_ALE_FIELD(super, 65, 1) ++DEFINE_ALE_FIELD(agable, 62, 1) ++DEFINE_ALE_FIELD(touched, 63, 1) ++DEFINE_ALE_FIELD(ucast_type, 62, 2) ++DEFINE_ALE_FIELD(port_num, 66, 4) ++DEFINE_ALE_FIELD(port_num_2g, 66, 1) ++DEFINE_ALE_FIELD(port_num_3g, 66, 2) ++DEFINE_ALE_FIELD(blocked, 65, 1) ++DEFINE_ALE_FIELD(secure, 64, 1) ++DEFINE_ALE_FIELD(oui_entry, 62, 2) ++DEFINE_ALE_FIELD(oui_addr, 4, 24) ++DEFINE_ALE_FIELD(mcast, 40, 1) ++DEFINE_ALE_FIELD(vlan_entry_type, 62, 3) ++DEFINE_ALE_FIELD(ethertype, 0, 16) ++DEFINE_ALE_FIELD(ipv4_addr, 0, 32) ++DEFINE_ALE_FIELD(ingress_bits, 65, 5) ++DEFINE_ALE_FIELD(ipv6_addr_low, 0, 60) ++DEFINE_ALE_FIELD(ipv6_addr_mid, 63, 8) ++DEFINE_ALE_FIELD(ipv6_addr_high, 0, 60) ++DEFINE_ALE_FIELD(entry_word0, 0, 32) ++DEFINE_ALE_FIELD(entry_word1, 32, 32) ++DEFINE_ALE_FIELD(entry_word2, 64, 12) ++ ++static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_MAC_OCTET; i++) ++ addr[i] = cpsw_ale_get_field(ale_entry, MAC_START_BIT - MAC_OCTET_LEN * i, ++ MAC_OCTET_LEN); ++} ++ ++struct k3_cpsw_regdump_hdr { ++ u32 module_id; ++ u32 len; ++}; ++ ++enum { ++ K3_CPSW_REGDUMP_MOD_NUSS = 1, ++ K3_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, ++ K3_CPSW_REGDUMP_MOD_MDIO = 3, ++ K3_CPSW_REGDUMP_MOD_CPSW = 4, ++ K3_CPSW_REGDUMP_MOD_CPSW_P0 = 5, ++ K3_CPSW_REGDUMP_MOD_CPSW_PN = 6, ++ K3_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE = 8, ++ K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, ++ K3_CPSW_REGDUMP_MOD_LAST, ++}; ++ ++static const char *mod_names[K3_CPSW_REGDUMP_MOD_LAST] = { ++ [K3_CPSW_REGDUMP_MOD_NUSS] = "cpsw-nuss", ++ [K3_CPSW_REGDUMP_MOD_RGMII_STATUS] = "cpsw-nuss-rgmii-status", ++ [K3_CPSW_REGDUMP_MOD_MDIO] = "cpsw-nuss-mdio", ++ [K3_CPSW_REGDUMP_MOD_CPSW] = "cpsw-nu", ++ [K3_CPSW_REGDUMP_MOD_CPSW_P0] = "cpsw-nu-p0", ++ [K3_CPSW_REGDUMP_MOD_CPSW_PN] = "cpsw-nu-pn", ++ [K3_CPSW_REGDUMP_MOD_CPSW_CPTS] = "cpsw-nu-cpts", ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE] = "cpsw-nu-ale", ++ [K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL] = "cpsw-nu-ale-tbl", ++}; ++ ++static void cpsw_ale_dump_oui_entry(int index, u32 *ale_entry) ++{ ++ u32 oui_addr; ++ ++ oui_addr = cpsw_ale_get_oui_addr(ale_entry); ++ ++ fprintf(stdout, "%d: Type: OUI Unicast\n, \tOUI = %02x:%02x:%02x\n", ++ index, (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, ++ (oui_addr >> OUI_ADDR_SHIFT) & OUI_ADDR_MASK, oui_addr & OUI_ADDR_MASK); ++} ++ ++static void cpsw_ale_dump_addr(int index, u32 *ale_entry) ++{ ++ u8 addr[NUM_MAC_OCTET]; ++ ++ cpsw_ale_get_addr(ale_entry, addr); ++ ++ if (cpsw_ale_get_mcast(ale_entry)) { ++ static const char * const str_mcast_state[] = {"Forwarding", ++ "Blocking/Forwarding/Learning", ++ "Learning/Forwarding", ++ "Forwarding"}; ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); ++ u8 super = cpsw_ale_get_super(ale_entry); ++ ++ fprintf(stdout, "%d: Type: Multicast\n \tAddress = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_State = %s, %sSuper, port_mask = 0x%x\n", ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], ++ str_mcast_state[state], super ? "" : "No ", port_mask); ++ } else { ++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", ++ "Touched"}; ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); ++ u8 port_num = cpsw_ale_get_port_num(ale_entry); ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); ++ u8 touched = cpsw_ale_get_touched(ale_entry); ++ u8 secure = cpsw_ale_get_secure(ale_entry); ++ u8 agable = cpsw_ale_get_agable(ale_entry); ++ ++ fprintf(stdout, "%d: Type: Unicast\n \tUpdated Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast Type = %s, Port_num = 0x%x, Secure: %d, Blocked: %d, Touch = %d, Agable = %d\n", ++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], ++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); ++ } ++} ++ ++static void cpsw_ale_dump_inner_vlan_entry(int index, u32 *ale_entry) ++{ ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); ++ ++ fprintf(stdout, "%d: Type: Inner VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); ++ ++ if (rtl_version == CPSW2G_RTL_VERSION) { ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); ++ ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); ++ } else { ++ fprintf(stdout, "\tVLAN ID = %d, Registered Mask = 0x%x, No Frag = %d\n", ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK, ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK); ++ ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x, Members = 0x%x\n", ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); ++ } ++} ++ ++static void cpsw_ale_dump_outer_vlan_entry(int index, u32 *ale_entry) ++{ ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); ++ ++ fprintf(stdout, "%d: Type: Outer VLAN\n \tNolearn Mask = 0x%x, Ingress Check = %d\n", ++ index, (vlan_entry_word2 >> NOLEARN_FLAG_SHIFT) & NOLEARN_FLAG_MASK, ++ (vlan_entry_word2 >> INGRESS_CHECK_SHIFT) & INGRESS_CHECK_MASK); ++ ++ if (rtl_version == CPSW2G_RTL_VERSION) { ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT_2G) & NOFRAG_FLAG_MASK_2G, ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); ++ ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Unregistered Mask = 0x%x, Limit Next Header Control = %d, Members = 0x%x\n", ++ (vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK_2G, ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT_2G) & UNREG_MASK_MASK_2G, ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT_2G) & NXT_HDR_CTRL_MASK_2G, ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK_2G)); ++ } else { ++ fprintf(stdout, "\tVLAN ID = %d, No Frag = %d, Registered Mask = 0x%x\n", ++ (vlan_entry_word1 >> VLAN_ID_SHIFT) & VLAN_ID_MASK, ++ (vlan_entry_word1 >> NOFRAG_FLAG_SHIFT) & NOFRAG_FLAG_MASK, ++ (vlan_entry_word1 >> REG_MASK_SHIFT) & REG_MASK_MASK); ++ ++ fprintf(stdout, "\tForce Untagged Packet Egress = 0x%x, Limit Next Header Control = %d, Unregistered Mask = 0x%x Members = 0x%x\n", ++ (vlan_entry_word1 & PKT_EGRESS_W1_MASK) * PKT_EGRESS_W1_OFFSET + ++ ((vlan_entry_word0 >> PKT_EGRESS_SHIFT) & PKT_EGRESS_MASK), ++ (vlan_entry_word0 >> NXT_HDR_CTRL_SHIFT) & NXT_HDR_CTRL_MASK, ++ (vlan_entry_word0 >> UNREG_MASK_SHIFT) & UNREG_MASK_MASK, ++ (vlan_entry_word0 & VLAN_MEMBER_LIST_MASK)); ++ } ++} ++ ++static void cpsw_ale_dump_ethertype_entry(int index, u32 *ale_entry) ++{ ++ u16 ethertype = cpsw_ale_get_ethertype(ale_entry); ++ ++ fprintf(stdout, "%d: Type: VLAN Ethertype\n \tEthertype = 0x%x\n", index, ethertype); ++} ++ ++static void cpsw_ale_dump_ipv4_entry(int index, u32 *ale_entry) ++{ ++ u8 ingress_bits = cpsw_ale_get_ingress_bits(ale_entry); ++ u32 ipv4_addr = cpsw_ale_get_ipv4_addr(ale_entry); ++ ++ fprintf(stdout, "%d: Type: VLAN IPv4\n \tIngress Bits: 0x%x IPv4 Address = %u.%u.%u.%u\n", ++ index, ingress_bits, ipv4_addr >> IPV4_ADDR_OCT1_SHIFT & IPV4_ADDR_MASK, ++ ipv4_addr >> IPV4_ADDR_OCT2_SHIFT & IPV4_ADDR_MASK, ++ ipv4_addr >> IPV4_ADDR_OCT3_SHIFT & IPV4_ADDR_MASK, ipv4_addr & IPV4_ADDR_MASK); ++} ++ ++static void cpsw_ale_dump_ipv6_entry(int index, u32 *ale_entry) ++{ ++ u32 vlan_entry_word0 = cpsw_ale_get_entry_word0(ale_entry); ++ u32 vlan_entry_word1 = cpsw_ale_get_entry_word1(ale_entry); ++ u16 vlan_entry_word2 = cpsw_ale_get_entry_word2(ale_entry); ++ ++ if (index & IPV6_HIGH_ENTRY_FLAG) { ++ fprintf(stdout, "%d: Type: VLAN IPv6 Higher Entry (Lower Bit entry at %04u)\n \tIgnored Multicast bits: 0x%x, IPv6 Address (Bits [127:68]) = %04x:%03x%01x:%04x:%03x\n", ++ index, (index & (~IPV6_HIGH_ENTRY_FLAG)), ++ vlan_entry_word2 & IPV6_IGNMCBITS_MASK, ++ (vlan_entry_word1 >> IPV6_HADDR_W1_SHIFT) & IPV6_HADDR_W1_MASK_1, ++ vlan_entry_word1 & IPV6_HADDR_W1_MASK_2, ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_1) & IPV6_HADDR_W0_MASK_1, ++ (vlan_entry_word0 >> IPV6_HADDR_W0_SHIFT_2) & IPV6_HADDR_W0_MASK_2, ++ vlan_entry_word0 & IPV6_HADDR_W0_MASK_2); ++ } else { ++ fprintf(stdout, "%d: Type: VLAN IPv6 Lower Entry (Higher Bit entry at %04u)\n \tIPv6 Address (Bits [127:68]) = %01x:%01x%03x:%04x:%04x:%04x\n", ++ index, (index | IPV6_HIGH_ENTRY_FLAG), ++ (vlan_entry_word2 >> IPV6_LADDR_W2_SHIFT) & IPV6_LADDR_W2_MAKS, ++ vlan_entry_word2 & IPV6_LADDR_W2_MAKS, ++ (vlan_entry_word1 >> IPV6_LADDR_W1_SHIFT) & IPV6_LADDR_W1_MASK_1, ++ vlan_entry_word1 & IPV6_LADDR_W1_MASK, ++ (vlan_entry_word0 >> IPV6_LADDR_W0_SHIFT) & IPV6_LADDR_W0_MASK, ++ vlan_entry_word0 & IPV6_LADDR_W0_MASK); ++ } ++} ++ ++static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry) ++{ ++ u8 addr[NUM_MAC_OCTET]; ++ int vlan = cpsw_ale_get_vlan_id(ale_entry); ++ ++ cpsw_ale_get_addr(ale_entry, addr); ++ if (cpsw_ale_get_mcast(ale_entry)) { ++ static const char * const str_mcast_state[] = {"Forwarding", ++ "Blocking/Forwarding/Learning", ++ "Learning/Forwarding", ++ "Forwarding"}; ++ u16 port_mask = cpsw_ale_get_port_mask(ale_entry); ++ u8 state = cpsw_ale_get_mcast_state(ale_entry); ++ u8 super = cpsw_ale_get_super(ale_entry); ++ ++ fprintf(stdout, "%d: Type: Multicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Multicast_state = %s, %s Super, port_mask = 0x%x\n", ++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], ++ str_mcast_state[state], super ? "" : "No ", port_mask); ++ } else { ++ static const char * const s_ucast_type[] = {"Persistent", "Untouched", "OUI", ++ "Touched"}; ++ u8 ucast_type = cpsw_ale_get_ucast_type(ale_entry); ++ u8 blocked = cpsw_ale_get_blocked(ale_entry); ++ u8 touched = cpsw_ale_get_touched(ale_entry); ++ u8 secure = cpsw_ale_get_secure(ale_entry); ++ u8 agable = cpsw_ale_get_agable(ale_entry); ++ ++ int port_num; ++ ++ if (rtl_version == CPSW2G_RTL_VERSION) ++ port_num = cpsw_ale_get_port_num_2g(ale_entry); ++ else if (rtl_version == CPSW3G_RTL_VERSION) ++ port_num = cpsw_ale_get_port_num_3g(ale_entry); ++ else ++ port_num = cpsw_ale_get_port_num(ale_entry); ++ ++ fprintf(stdout, "%d: Type: Unicast\n \tVID = %d, Address = %02x:%02x:%02x:%02x:%02x:%02x, Unicast_type = %s, port_num = 0x%x, Secure = %d, Blocked = %d, Touch = %d, Agable = %d\n", ++ index, vlan, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], ++ s_ucast_type[ucast_type], port_num, secure, blocked, touched, agable); ++ } ++} ++ ++void cpsw_dump_ale(struct k3_cpsw_regdump_hdr *ale_hdr, u32 *ale_pos) ++{ ++ int i, ale_entries; ++ ++ if (!ale_hdr) ++ return; ++ ++ ale_entries = (ale_hdr->len - sizeof(struct k3_cpsw_regdump_hdr)) / ++ ALE_ENTRY_WORDS / sizeof(u32); ++ ++ printf("Number of ALE entries: %d\n", ale_entries); ++ ale_pos += 2; ++ for (i = 0; i < ale_entries; i++) { ++ int type; ++ ++ type = cpsw_ale_get_entry_type(ale_pos); ++ ++ switch (type) { ++ case ALE_ENTRY_FREE: ++ break; ++ ++ case ALE_ENTRY_ADDR: ++ u32 oui_entry = cpsw_ale_get_oui_addr(ale_pos); ++ ++ if (oui_entry == 0x2) ++ cpsw_ale_dump_oui_entry(i, ale_pos); ++ else ++ cpsw_ale_dump_addr(i, ale_pos); ++ break; ++ ++ case ALE_ENTRY_VLAN: ++ u32 vlan_entry_type = cpsw_ale_get_vlan_entry_type(ale_pos); ++ ++ if (vlan_entry_type == VLAN_INNER_ENTRY) ++ cpsw_ale_dump_inner_vlan_entry(i, ale_pos); ++ else if (vlan_entry_type == VLAN_OUTER_ENTRY) ++ cpsw_ale_dump_outer_vlan_entry(i, ale_pos); ++ else if (vlan_entry_type == VLAN_ETHERTYPE_ENTRY) ++ cpsw_ale_dump_ethertype_entry(i, ale_pos); ++ else if (vlan_entry_type == VLAN_IPV4_ENTRY) ++ cpsw_ale_dump_ipv4_entry(i, ale_pos); ++ else if (vlan_entry_type & VLAN_IPV6_ENTRY_MASK) ++ cpsw_ale_dump_ipv6_entry(i, ale_pos); ++ break; ++ ++ case ALE_ENTRY_VLAN_ADDR: ++ cpsw_ale_dump_vlan_addr(i, ale_pos); ++ break; ++ ++ default: ++ break; ++ } ++ ++ ale_pos += ALE_ENTRY_WORDS; ++ } ++} ++ ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused, ++ struct ethtool_regs *regs) ++{ ++ struct k3_cpsw_regdump_hdr *dump_hdr, *ale_hdr = NULL; ++ u32 *reg = (u32 *)regs->data, *ale_pos; ++ u32 mod_id; ++ int i, regdump_len = info->regdump_len; ++ ++ fprintf(stdout, "K3 CPSW dump version: %d, len: %d\n", ++ regs->version, info->regdump_len); ++ fprintf(stdout, "(Missing registers in memory space can be considered as zero valued)\n"); ++ ++ /* Line break before register dump */ ++ fprintf(stdout, "--------------------------------------------------------------------\n"); ++ i = 0; ++ do { ++ u32 *tmp, j; ++ u32 num_items; ++ ++ dump_hdr = (struct k3_cpsw_regdump_hdr *)reg; ++ mod_id = dump_hdr->module_id; ++ ++ num_items = dump_hdr->len / sizeof(u32); ++ ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE) ++ rtl_version = reg[3] & RTL_VERSION_MASK; ++ ++ if (mod_id == K3_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { ++ ale_hdr = dump_hdr; ++ ale_pos = reg; ++ break; ++ } ++ ++ fprintf(stdout, "%s regdump: number of Registers:(%d)\n", ++ mod_names[mod_id], num_items - 2); ++ tmp = reg; ++ /* Values are stored in pair as reg_offset-reg_val, hence parse the same way*/ ++ for (j = 2; j < num_items; j += 2) { ++ if (tmp[j + 1] != 0x0) ++ fprintf(stdout, "%08x:reg(%08X)\n", tmp[j], tmp[j + 1]); ++ } ++ ++ reg += num_items; ++ i += dump_hdr->len; ++ } while (i < regdump_len); ++ ++ /* Adding a boundary in between Register dump and ALE table */ ++ fprintf(stdout, "--------------------------\n"); ++ ++ cpsw_dump_ale(ale_hdr, ale_pos); ++ ++ return 0; ++}; +diff --git a/ethtool.c b/ethtool.c +index 3ac15a7..a383eb6 100644 +--- a/ethtool.c ++++ b/ethtool.c +@@ -1162,6 +1162,7 @@ static const struct { + { "fsl_enetc", fsl_enetc_dump_regs }, + { "fsl_enetc_vf", fsl_enetc_dump_regs }, + { "hns3", hns3_dump_regs }, ++ { "am65-cpsw-nuss", am65_cpsw_dump_regs }, + }; + #endif + +diff --git a/internal.h b/internal.h +index 4b994f5..81212b4 100644 +--- a/internal.h ++++ b/internal.h +@@ -410,4 +410,7 @@ int cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); + /* Microchip Ethernet Controller */ + int lan743x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); + ++/* TI K3 CPSW Ethernet Switch */ ++int am65_cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); ++ + #endif /* ETHTOOL_INTERNAL_H__ */ +-- +2.34.1 + diff --git a/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend new file mode 100644 index 00000000..3b388151 --- /dev/null +++ b/meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend @@ -0,0 +1,4 @@ +ETHTOOL_ARAGO = "" +ETHTOOL_ARAGO:arago = "ethtool-arago.inc" + +require ${ETHTOOL_ARAGO}
Add support for TI K3 CPSW register and ALE table dump through the ethtool userspace utility. Signed-off-by: Aniket Limaye <a-limaye@ti.com> --- .../ethtool/ethtool-arago.inc | 8 + ...k3-cpsw-registers-and-ale-table-dump.patch | 574 ++++++++++++++++++ .../ethtool/ethtool_%.bbappend | 4 + 3 files changed, 586 insertions(+) create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool-arago.inc create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool/pretty-add-support-for-ti-k3-cpsw-registers-and-ale-table-dump.patch create mode 100644 meta-arago-distro/recipes-extended/ethtool/ethtool_%.bbappend