xref: /aosp_15_r20/external/ethtool/cpsw.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Code to dump registers for TI CPSW switch devices.
3  *
4  * Copyright (c) 2022 Linutronix GmbH
5  * Author: Benedikt Spranger <[email protected]>
6  */
7 
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include "internal.h"
12 
13 #define ALE_ENTRY_BITS		68
14 #define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32)
15 #define ALE_ENTRY_BYTES (ALE_ENTRY_WORDS * 4)
16 
17 struct address_table_entry
18 {
19 	u8 port;
20 	u8 reserved1;
21 	u8 reserved2;
22 	u8 reserved3;
23 	u8 addr2;
24 	u8 addr1;
25 	u16 vlan;
26 	u8 addr6;
27 	u8 addr5;
28 	u8 addr4;
29 	u8 addr3;
30 } __attribute__((packed));
31 
32 struct vlan_table_entry
33 {
34 	u8 reserved1;
35 	u8 reserved2;
36 	u8 reserved3;
37 	u8 reserved4;
38 	u8 reserved5;
39 	u8 reserved6;
40 	u16 vlan;
41 	u8 member;
42 	u8 mc_unreg;
43 	u8 mc_reg;
44 	u8 untag;
45 } __attribute__((packed));
46 
47 union ale_entry {
48 	struct address_table_entry addr;
49 	struct vlan_table_entry vlan;
50 	u32 val[3];
51 	u8 byte[12];
52 };
53 
54 enum entry_type {
55 	FREE_ENTRY = 0,
56 	ADDR_ENTRY,
57 	VLAN_ENTRY,
58 	VLAN_ADDR_ENTRY,
59 	LAST_ENTRY
60 };
61 
62 static char *fwd_state_name[] = {
63 	"Forwarding",
64 	"Blocking/Forwarding/Learning",
65 	"Forwarding/Learning",
66 	"Forwarding",
67 };
68 
69 static char *type_name[] = {
70 	"free entry",
71 	"address entry",
72 	"VLAN entry",
73 	"VLAN address entry",
74 	"invalid"
75 };
76 
decode_type(union ale_entry * entry)77 enum entry_type decode_type(union ale_entry *entry)
78 {
79 	/* Entry Type (61:60) */
80 	return (entry->byte[7] >> 4) & 0x3;
81 }
82 
print_addr(u8 * data)83 static void print_addr(u8 *data)
84 {
85 	printf("%02x:%02x:%02x:%02x:%02x:%02x",
86 	       data[5], data[4], data[11], data[10], data[9], data[8]);
87 }
88 
decode_multi_addr(union ale_entry * entry,int vlan)89 static void decode_multi_addr(union ale_entry *entry, int vlan)
90 {
91 	printf("      MULTI: ");
92 	print_addr(entry->byte);
93 	printf(" %s", fwd_state_name[entry->addr.vlan >> 14]);
94 	printf("%s", (entry->addr.port & 0x02) ? " Super" : "");
95 	printf(" Ports: 0x%x", (entry->addr.port >> 2) & 0x3);
96 	if (vlan)
97 		printf(" VLAN: %04d", entry->addr.vlan & 0x0fff);
98 	printf("\n");
99 }
100 
decode_uni_addr(union ale_entry * entry,int vlan)101 static void decode_uni_addr(union ale_entry *entry, int vlan)
102 {
103 	printf("      UNI  : ");
104 	print_addr(entry->byte);
105 	printf("%s", (entry->addr.port & 0x01) ? " Secure" : "");
106 	printf("%s", (entry->addr.port & 0x02) ? " Block" : "");
107 	printf("%s", (entry->addr.port & 0x20) ? " DLR" : "");
108 	printf(" Ports: 0x%x", (entry->addr.port >> 2) & 0x3);
109 	if (vlan)
110 		printf(" VLAN: %04d", entry->addr.vlan & 0x0fff);
111 	printf("\n");
112 }
113 
decode_oui_addr(union ale_entry * entry)114 static void decode_oui_addr(union ale_entry *entry)
115 {
116 	printf("      OUI  : ");
117 	print_addr(entry->byte);
118 	printf("\n");
119 }
120 
decode_vlan(union ale_entry * entry)121 static void decode_vlan(union ale_entry *entry)
122 {
123 	printf("      VLAN ");
124 	printf("%04d: ", entry->vlan.vlan & 0x0fff);
125 	printf("member: 0x%x ", entry->vlan.member & 0x7);
126 	printf("mc flood unreg: 0x%x ", entry->vlan.mc_unreg & 0x7);
127 	printf("mc flood reg: 0x%x ", entry->vlan.mc_reg & 0x7);
128 	printf("untag: 0x%x\n", entry->vlan.untag & 0x7);
129 }
130 
decode_ale_entry(unsigned int idx,const u8 * data,bool last_was_free)131 static enum entry_type decode_ale_entry(unsigned int idx, const u8 *data,
132 					bool last_was_free)
133 {
134 	union ale_entry *entry = (union ale_entry *) data;
135 	enum entry_type type;
136 
137 	entry = entry + idx;
138 	type = decode_type(entry);
139 
140 	if (!last_was_free || type != FREE_ENTRY)
141 		printf("%04d: %s\n", idx, type_name[type]);
142 
143 	switch (type)
144 	{
145 	case FREE_ENTRY:
146 		goto out;
147 		break;
148 
149 	case ADDR_ENTRY:
150 		/* Multicast: OUI 01:00:5e:xx:xx:xx */
151 		if (entry->addr.addr1 == 0x01)
152 			decode_multi_addr(entry, 0);
153 		else
154 			if ((entry->addr.vlan >> 14) == 0x2)
155 				decode_oui_addr(entry);
156 			else
157 				decode_uni_addr(entry, 0);
158 		break;
159 
160 	case VLAN_ENTRY:
161 		decode_vlan(entry);
162 		break;
163 
164 	case VLAN_ADDR_ENTRY:
165 		/* Check for Individual/Group bit */
166 		if (entry->addr.addr1 & 0x01)
167 			decode_multi_addr(entry, 1);
168 		else
169 			decode_uni_addr(entry, 1);
170 		break;
171 
172 	default:
173 		printf("internal failure.\n");
174 	}
175 
176 out:
177 	return type;
178 }
179 
cpsw_dump_regs(struct ethtool_drvinfo * info __maybe_unused,struct ethtool_regs * regs)180 int cpsw_dump_regs(struct ethtool_drvinfo *info __maybe_unused,
181 		   struct ethtool_regs *regs)
182 {
183 	unsigned int entries = regs->len/ALE_ENTRY_BYTES;
184 	enum entry_type type = LAST_ENTRY;
185 	unsigned int i;
186 
187 	printf("ALE Entries (%d):\n", entries);
188 
189 	for (i = 0; i < entries; i++)
190 		type = decode_ale_entry(i, regs->data, (type == FREE_ENTRY));
191 
192 	return 0;
193 }
194