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