Files
RTLPlayground/doc/l2.md
T
d00f 4a78b2dc8c doc: move the L2 multicast and tag word details out of the code
Review asked for this directly: the hardware layout above port_l2mc_set()
would be better as documentation than as a comment, keeping only the two
lines that say what the function does.

doc/l2.md gains a section on static multicast entries, why delivery uses
the forward action rather than the trap, and the SMI layout of the entry.
doc/CpuPort.md gains the layout of the tag's flags and pmask words, with
the byte order trap that cost an afternoon: writing the flags constant raw
instead of through HTONS puts 0x0020 on the wire as 0x2000, which is EFID
rather than LEARN_DIS, and the ASIC then leaves the 0x8899 header on the
frame.

The comments those paragraphs came from are replaced by a pointer to the
file that now holds them.
2026-08-18 23:29:10 +02:00

101 lines
4.2 KiB
Markdown

# L2
The RTL827x provides access and configuration options to an L2 table that
is used to associate device-MACs with ports on which those devices can
be reached in the LAN. The code so far configures automatic learning and
uses a default for aging of the learned addresses.
## L2 Tables
Access to the tables is done using table access registers. The same access
registers also provide access to the VLAN configuration tables. An idea of how
the table works can be gained from the [RTL8369 Datasheet](http://realtek.info/pdf/rtl8366_8369_datasheet_1-1.pdf)
section 8.17 and in particular table 20.
The central table register is RTL837X_TBL_CTRL(0x5cac).
```
Register RTL837X_TBL_CTRL bytes: EE EE TT CC
EE: Entry
TT: Table type
CC: Command (Bit 0: Execute, Bit 1: Write)
TT: 04: TBL_L2_UNICAST, 03: TBL_VLAN
```
An entry is retrieved from the tables by setting the data in registers to the
desired entry filter, then executing a table command by writing to RTL837X_TBL_CTRL
with execute bit 0 set, table type set and entry identifier (VLAN-Id or hash for L2).
Data will be fetched from the table and is available once the execute bit has been
cleared by the ASIC. Data then is in the output data registers
```
#define RTL837x_L2_DATA_OUT_A 0x5ccc
#define RTL837x_L2_DATA_OUT_B 0x5cd0
#define RTL837x_L2_DATA_OUT_C 0x5cd4
DATA_OUT_A DATA_OUT_B L2_DATA_OUT_C
M2 M3 M4 M5 fV VV M0 M1 xx xF xx gg
M0-M5: 6 bytes of MAC, M0 is MSB
V: 12 bits of VLAN-ID
f: bit 5 set: Entry is valid, otherwise stale
bit 6: bit 0 of port-number
bit 7: bit 1 of port-number
g: bit 0: bit 2 of port-number
bit 1: bit 3 of port-number (MSB)
bit 2: bit 0 of entry-age
bit 3: bit 1 of entry-age
bit 4: bit 2 of entry-age (MSB)
F: bit 0: entry is static(1) or learned (0)
```
The next entry can be now found in RTL837x_TBL_DATA_0 (entry = RTL837x_TBL_DATA_0_bits(0-11) + 1),
which can be used to get the next entry by writing this value to RTL837X_TBL_CTRL
and executing again for the given table type. This entry number is probably a hash, for which
the algorithm is unknown.
Deleting the entire L2 table is done by checking and setting 0x53dc to 0x0, then writing
0x00010000 to register RTL837x_L2_TBL_CTRL and waiting until the bit 16 that was
set has cleared.
## API support in the code
The RTLPlayground code provides support for reading the L2 tables from the
ASIC and flushing the table in order to quickly forget the learned entries.
```
> l2
MAC VLAN type port
3c:18:a0:7e:11:00 0x0001 learned 5
1c:2a:a3:23:00:02 0x0001 learned 7
```
## Static multicast entries
Slow-protocol frames such as LACPDUs and STP BPDUs have to reach the CPU
without being flooded to the other ports. No bridge relays these frames:
their addresses are in the set that 802.1D-2004 clause 7.12.6 forbids a
bridge to forward, and what travels the network is the information, with
every bridge regenerating BPDUs of its own on its designated ports. The reserved-multicast *trap* action
cannot do that on this hardware, because its destination is an external CPU
attached to a physical port, which these boards do not populate. The protocol
modules therefore leave the reserved-multicast action at *forward* and constrain
the egress with a static L2 multicast entry instead: the lookup hits the entry's
own port mask rather than the VLAN flood mask. Verified on a SWTGW218AS both
ways, with the CPU bit cleared, where delivery stops, and with the CPU bit alone,
where nothing egresses.
`port_l2mc_set()` writes one such entry. The SMI layout is the L2 multicast
variant of the table entry:
```
DATA_IN_A = MAC bytes 5..2 -> c2 00 00 <mac_last>
DATA_IN_B = MAC[1..0] | vid<<16 | IVL<<29 | pmask[1:0]<<30
DATA_IN_C = pmask[9:2]
```
Lookups are IVL, so an entry made for VID 0 is never matched and a caller adds
one entry per PVID in use. The write goes through the table access register
with the table selector set to the L2 lookup table, `TBL_L2_UNICAST` in the
code, a name that despite appearances covers the multicast entries as well.
The hardware hashes MAC and VID to pick the bucket slot by itself.
Writing the same MAC and VID again replaces the entry rather than adding a
second one, so a caller can retarget the mask at will, for instance back to all
ports to restore flooding.