lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20220712120114.3219-2-b.spranger@linutronix.de>
Date:   Tue, 12 Jul 2022 14:01:14 +0200
From:   Benedikt Spranger <b.spranger@...utronix.de>
To:     netdev@...r.kernel.org
Subject: [PATCH ethtool 1/1] pretty: Add support for TI CPSW register dumps

Add pretty register dump for the ALE table of the cpsw kernel drivers.

Signed-off-by: Benedikt Spranger <b.spranger@...utronix.de>
Reviewed-by: Kurt Kanzenbach <kurt@...utronix.de>
---
 Makefile.am |   2 +-
 cpsw.c      | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 ethtool.c   |   1 +
 internal.h  |   3 +
 4 files changed, 198 insertions(+), 1 deletion(-)
 create mode 100644 cpsw.c

diff --git a/Makefile.am b/Makefile.am
index dc5fbec..e1eabe2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,7 +18,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
+		  igc.c cmis.c cmis.h bnxt.c cpsw.c
 endif
 
 if ENABLE_BASH_COMPLETION
diff --git a/cpsw.c b/cpsw.c
new file mode 100644
index 0000000..68dcfac
--- /dev/null
+++ b/cpsw.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Code to dump registers for TI CPSW switch devices.
+ *
+ * Copyright (c) 2022 Linutronix GmbH
+ * Author: Benedikt Spranger <b.spranger@...utronix.de>
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "internal.h"
+
+#define ALE_ENTRY_BITS		68
+#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32)
+#define ALE_ENTRY_BYTES (ALE_ENTRY_WORDS * 4)
+
+struct address_table_entry
+{
+	u8 port;
+	u8 reserved1;
+	u8 reserved2;
+	u8 reserved3;
+	u8 addr2;
+	u8 addr1;
+	u16 vlan;
+	u8 addr6;
+	u8 addr5;
+	u8 addr4;
+	u8 addr3;
+} __attribute__((packed));
+
+struct vlan_table_entry
+{
+	u8 reserved1;
+	u8 reserved2;
+	u8 reserved3;
+	u8 reserved4;
+	u8 reserved5;
+	u8 reserved6;
+	u16 vlan;
+	u8 member;
+	u8 mc_unreg;
+	u8 mc_reg;
+	u8 untag;
+} __attribute__((packed));
+
+union ale_entry {
+	struct address_table_entry addr;
+	struct vlan_table_entry vlan;
+	u32 val[3];
+	u8 byte[12];
+};
+
+enum entry_type {
+	FREE_ENTRY = 0,
+	ADDR_ENTRY,
+	VLAN_ENTRY,
+	VLAN_ADDR_ENTRY,
+	LAST_ENTRY
+};
+
+static char *fwd_state_name[] = {
+	"Forwarding",
+	"Blocking/Forwarding/Learning",
+	"Forwarding/Learning",
+	"Forwarding",
+};
+
+static char *type_name[] = {
+	"free entry",
+	"address entry",
+	"VLAN entry",
+	"VLAN address entry",
+	"invalid"
+};
+
+enum entry_type decode_type(union ale_entry *entry)
+{
+	/* Entry Type (61:60) */
+	return (entry->byte[7] >> 4) & 0x3;
+}
+
+static void print_addr(u8 *data)
+{
+	printf("%02x:%02x:%02x:%02x:%02x:%02x",
+	       data[5], data[4], data[11], data[10], data[9], data[8]);
+}
+
+static void decode_multi_addr(union ale_entry *entry, int vlan)
+{
+	printf("      MULTI: ");
+	print_addr(entry->byte);
+	printf(" %s", fwd_state_name[entry->addr.vlan >> 14]);
+	printf("%s", (entry->addr.port & 0x02) ? " Super" : "");
+	printf(" Ports: 0x%x", (entry->addr.port >> 2) & 0x3);
+	if (vlan)
+		printf(" VLAN: %04d", entry->addr.vlan & 0x0fff);
+	printf("\n");
+}
+
+static void decode_uni_addr(union ale_entry *entry, int vlan)
+{
+	printf("      UNI  : ");
+	print_addr(entry->byte);
+	printf("%s", (entry->addr.port & 0x01) ? " Secure" : "");
+	printf("%s", (entry->addr.port & 0x02) ? " Block" : "");
+	printf("%s", (entry->addr.port & 0x20) ? " DLR" : "");
+	printf(" Ports: 0x%x", (entry->addr.port >> 2) & 0x3);
+	if (vlan)
+		printf(" VLAN: %04d", entry->addr.vlan & 0x0fff);
+	printf("\n");
+}
+
+static void decode_oui_addr(union ale_entry *entry)
+{
+	printf("      OUI  : ");
+	print_addr(entry->byte);
+	printf("\n");
+}
+
+static void decode_vlan(union ale_entry *entry)
+{
+	printf("      VLAN ");
+	printf("%04d: ", entry->vlan.vlan & 0x0fff);
+	printf("member: 0x%x ", entry->vlan.member & 0x7);
+	printf("mc flood unreg: 0x%x ", entry->vlan.mc_unreg & 0x7);
+	printf("mc flood reg: 0x%x ", entry->vlan.mc_reg & 0x7);
+	printf("untag: 0x%x\n", entry->vlan.untag & 0x7);
+}
+
+static enum entry_type decode_ale_entry(unsigned int idx, const u8 *data,
+					bool last_was_free)
+{
+	union ale_entry *entry = (union ale_entry *) data;
+	enum entry_type type;
+
+	entry = entry + idx;
+	type = decode_type(entry);
+
+	if (!last_was_free || type != FREE_ENTRY)
+		printf("%04d: %s\n", idx, type_name[type]);
+
+	switch (type)
+	{
+	case FREE_ENTRY:
+		goto out;
+		break;
+
+	case ADDR_ENTRY:
+		/* Multicast: OUI 01:00:5e:xx:xx:xx */
+		if (entry->addr.addr1 == 0x01)
+			decode_multi_addr(entry, 0);
+		else
+			if ((entry->addr.vlan >> 14) == 0x2)
+				decode_oui_addr(entry);
+			else
+				decode_uni_addr(entry, 0);
+		break;
+
+	case VLAN_ENTRY:
+		decode_vlan(entry);
+		break;
+
+	case VLAN_ADDR_ENTRY:
+		/* Check for Individual/Group bit */
+		if (entry->addr.addr1 & 0x01)
+			decode_multi_addr(entry, 1);
+		else
+			decode_uni_addr(entry, 1);
+		break;
+
+	default:
+		printf("internal failure.\n");
+	}
+
+out:
+	return type;
+}
+
+int cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused,
+		   struct ethtool_regs *regs)
+{
+	unsigned int entries = regs->len/ALE_ENTRY_BYTES;
+	enum entry_type type = LAST_ENTRY;
+	unsigned int i;
+
+	printf("ALE Entries (%d):\n", entries);
+
+	for (i = 0; i < entries; i++)
+		type = decode_ale_entry(i, regs->data, (type == FREE_ENTRY));
+
+	return 0;
+}
diff --git a/ethtool.c b/ethtool.c
index 911f26b..517cdc5 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1129,6 +1129,7 @@ static const struct {
 	{ "fec", fec_dump_regs },
 	{ "igc", igc_dump_regs },
 	{ "bnxt_en", bnxt_dump_regs },
+	{ "cpsw-switch", cpsw_dump_regs },
 };
 #endif
 
diff --git a/internal.h b/internal.h
index 0d9d816..9c4b86a 100644
--- a/internal.h
+++ b/internal.h
@@ -412,4 +412,7 @@ int igc_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 /* Broadcom Ethernet Controller */
 int bnxt_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 
+/* TI CPSW Ethernet Switch */
+int cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
 #endif /* ETHTOOL_INTERNAL_H__ */
-- 
2.36.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ