57 Commits
Author SHA1 Message Date
avicarmeli b28ead65dc Add Hasivo S1100P-8GT-1SX-S hardware profile (#585)
* Add Hasivo board definition and documentation Hasivo S1100P
2026-10-20 09:43:59 +02:00
logicog a079c803d9 Merge pull request #611 from hlyi/machine_refactoring
More clean up machine c files. Add SKS3200_8E1X
2026-10-20 05:58:46 +02:00
d00f cc3ae654a0 Merge pull request #644 from vankxr/fix/nic-wrap
nic: Fix incorrect wrap handling of RX circular buffer
2026-10-20 02:20:09 +02:00
René van Dorst 57d6337940 Merge pull request #650 from Kamikaze94/device/hc-swtg124as
Add Horaco HC-SWTG124AS device
2026-10-19 20:34:43 +00:00
René van Dorst 3b58eb36e5 Merge pull request #653 from andrebrait/docs/horaco-swtgw218as-v2.1
doc: Horaco HC-SWTGW218AS on PCB SWTG118AS-V2.1
2026-10-19 20:29:05 +00:00
Andre Brait 34c0ef77d0 doc: move CPU identification guidance into the device guide
Address review by documenting regget 4 and RTL8373 N/non-N ID values under Step 4 of adding-a-device.md, without referring to a particular board or set of units. Keep the verified Horaco CPU and flash capacity in its device table and retain the unverified-chip caveat.
2026-10-19 22:17:07 +02:00
Kamikaze94 e6182dbe0d docs: Added details to other models 2026-10-19 22:13:40 +02:00
Andre Brait 1d5e4cd722 doc: identify the Horaco SWTG118AS-V2.1 CPU and flash capacity
Read register 0x0004 on all three tested HC-SWTGW218AS units. Each returned 0x83730000, identifying RTL8373 rather than RTL8373N. Firmware reports 2 MB flash on all three.

Fill in the verified device-table fields and document the non-N/N register distinction. Leave PHY and flash-chip models explicitly unverified.
2026-10-19 22:09:42 +02:00
Kamikaze94 a02116a24b docs: Added HC-SWTG124AS RTL + flash chip 2026-10-19 21:46:43 +02:00
João Silva 98369c37fe nic: Fix incorrect wrap handling of RX circular buffer
nic: move other nic functions into the dedicated nic files
uip: alloc buffer multiple of 8 bytes

Signed-off-by: João Silva <jgc3silva@gmail.com>
2026-10-19 19:21:47 +01:00
René van Dorst 138acfadb1 Merge pull request #625 from vankxr/device/ys25-0402
Add YuanLey YS25-0402M device
2026-10-19 18:15:01 +00:00
João Silva 08f8498b39 Add reset button GPIO for YS25-0402M
Add chip name for YS25-0402M

Signed-off-by: João Silva <jgc3silva@gmail.com>
2026-10-19 18:58:03 +01:00
René van Dorst dd521cc79d Merge pull request #655 from vankxr/device/2g08110gsn
Add MokerLink 2G08110GSN device
2026-10-19 17:46:57 +00:00
João Silva 2c2349dcef Add MokerLink 2G08110GSN
Signed-off-by: João Silva <jgc3silva@gmail.com>
2026-10-19 12:36:23 +01:00
logicog 6d1380fb36 Merge pull request #632 from gtytup/2g5f4-10g2-v1.01-v2
New Device: Add support for the hongyavision HYWS-SGT0204S (2G5F4_10G2_V1.01)
2026-10-19 06:27:18 +02:00
Andre Brait eacf13690c doc: Horaco HC-SWTGW218AS on PCB SWTG118AS-V2.1
The HC-SWTGW218AS is listed only with the SWTG018AS-A V2.0 board, but it
also ships with SWTG118AS-V2.1, the board of the XikeStor SKS3200-8E1X.
That version runs MACHINE=SWTGW218AS: three such switches were flashed
through the OEM web upgrade and work.

Note in the device page that the model name alone does not tell which
firmware to build.
2026-10-19 03:45:29 +02:00
Kamikaze94 4ed74f05db Add machine definition for HC-SWTG124AS 2026-10-18 23:07:23 +02:00
João Silva 0de18ff457 Add YS25-0402M
Signed-off-by: João Silva <jgc3silva@gmail.com>
2026-10-18 21:16:34 +01:00
René van Dorst 3195a14870 Merge pull request #620 from hlyi/doc-fixes
Updates for GoodTop GT-ST018M
2026-10-18 19:58:34 +00:00
HL Yi 3ffb311e95 fixed doc for GT-ST018M and add device for GT-ST018M 2026-10-18 09:56:38 -05:00
René van Dorst 41ed689ae0 Merge pull request #624 from DrDoof/fix/readme-lag-link
doc: point the link aggregation entry at the document that exists
2026-10-18 08:14:35 +00:00
René van Dorst 11eadc5a49 Merge pull request #647 from tofurky/PCB-K0402WS-V1.0
Add support for YuanLey YS25-0402 (PCB-K0402WS-V1.0) + misc. doc cleanups
2026-10-18 08:05:35 +00:00
René van Dorst 24d2cd7bab Merge pull request #645 from hlyi/main-noconst
Non-functional changes for portability
2026-10-18 07:43:32 +00:00
Victor 28c09737b2 docs: 2G5F4_10G2_V1.01: case photos, nameplate details, serial header position
Add the assembled top, front and bottom of the case next to the PCB photos, and
record what the nameplate says (manufacturer, the model description translated
from the Chinese label, 12 V DC 2 A and the serial number format) so a device
can be identified by its label. The top of the case carries no model name.

Also point out where the three console through-holes sit in the top side photo
and note the PWR and SFP1/SFP2 LEDs on the front panel; the case legend for the
copper LEDs reads 1000M/2500M.
2026-10-18 10:12:22 +08:00
Victor 3e1d3f40d2 docs: add board photos for the 2G5F4_10G2_V1.01 (HYWS-SGT0204S)
Top and bottom of the PCB plus the stock Bright Moon T25S40 flash chip, using
the doc/devices/photos/<device>/ layout of the other device documents.
2026-10-18 10:12:22 +08:00
Victor 389dc2af76 machine: add the 2G5F4_10G2_V1.01 (HYWS-SGT0204S) target
The hongyavision HYWS-SGT0204S is sold as an unmanaged 4x2.5G + 2x10G SFP+
switch and carries the 2G5F4_10G2_V1.01 marking on the PCB. It is a sibling of
the KP-9000-6XH-X2 (2M-PCB43-V1.1), so machine/2G5F4_10G2_V1_01.c is that board
definition with these changes:

- The two SFP+ cages (physical ports 5 and 6) are wired the other way round:
  physical 5 is on SDS1 with GPIO30/GPIO37, physical 6 on SDS0 with
  GPIO50/GPIO10. Copper ports 1-4 match the KP-9000 layout.
- No reset button is fitted and the case has no opening for one, so reset_pin
  is GPIO_NA. GPIO54, the reset pin on the KP-9000 layout, reads as permanently
  pressed here.
- The board definition sets flash_sio, so the flash is read with single-IO: the
  fitted 512 KB Bright Moon T25S40 cannot be read in DIO mode on this board, an
  image that leaves DIO enabled does not come up at all, while the same image
  with single-IO boots and runs normally (two units).
- The board is added to the machine_custom_init() group that sets
  LED_GLB_IO_EN bit 6, otherwise the RTL837x "solid" conditions (LINK/speed)
  never drive the LEDs and the 2.5G LED glows faintly at 100M/1000M.

flash_sio is a new field of struct machine that rtlplayground.c hands to
flash_init(); only this board sets it, every other machine keeps DIO. It costs
management-plane speed only, the ASIC keeps forwarding in hardware.

The stock firmware runs a factory test console on the serial header at 9600
baud, whose silkscreen labels are shifted by one pin.

Verified: warning-free build, `make machine_check` passes for every target, the
host tests pass, and a control build of this target without the LED hook differs
from the KP-9000-6XH_X2_V1_1 image in 44 bytes: all inside the machine
description (including flash_sio) and the image CRC16, nothing else in the
firmware moved. On the board the single-IO image boots and runs on two units;
port order, SFP cages and LED behaviour come from the machine definition
verified on this board earlier.
2026-10-18 10:12:22 +08:00
Matt Merhar 4963fbe50a Add support for YuanLey YS25-0402 (PCB-K0402WS-V1.0)
UART is broken out to the unpopulated switch header at the front of the
board.

This isn't quite the same as the V2.0 definition as the system led is
always on, not routed through the CPU.

Additionally, document that the newer revision of the same "YS25-0402"
is supported via the existing PCB-K0402WS-V3.0 target.
2026-10-17 18:51:45 -04:00
Matt Merhar 44b5ab0e64 Fix typos in PCB-K0402WS-V3.0 board marking doc 2026-10-17 17:53:17 -04:00
Matt Merhar 088321deaf Fix typo in docs - SICSOLINK, not Siscolink 2026-10-17 17:53:15 -04:00
Matt Merhar 3af1b049ee Fix sort/spacing/stylization in supported_devices.md 2026-10-17 17:53:12 -04:00
HL Yi 6a5d3cdf2c change constant to macros and move RXIE enable to boot.c for portability. 2026-10-17 16:42:39 -05:00
feelfree69 d21ea52c46 Merge pull request #642 from vankxr/fix/dhcp-bank-mismatch
dhcp: Fix constants in different bank from code
2026-10-17 21:25:14 +02:00
João Silva c6cc3ee595 dhcp: Fix constants in different bank from code
Signed-off-by: João Silva <jgc3silva@gmail.com>
2026-10-17 18:46:54 +01:00
feelfree69 424a963301 Merge pull request #636 from sanchosk/patch-1
Fixing ONT-S207CW-62TS-SE.md readme
2026-10-17 13:13:36 +02:00
Robert Klauco 1344e02fb7 Update ONT-S207CW-62TS-SE.md
Updated the readme to differentiate between identifier tag and the compilation command.
Added also a line for flashing using GUI.
2026-10-17 12:40:00 +02:00
feelfree69 2ae297bc20 Merge pull request #637 from sanchosk/main
Update README.md - typo
2026-10-17 12:31:49 +02:00
Robert Klauco ce77cc273d Update README.md - typo
missing folder / in the path for update using OEM web updater
2026-10-17 11:56:12 +02:00
Robert Klauco 6376a10288 Fixing ONT-S207CW-62TS-SE.md readme
The MACHINE parameter was incorrect, fixed the _ with =
2026-10-17 11:34:03 +02:00
hlyi 6fdb19f18c Merge branch 'logicog:main' into machine_refactoring 2026-10-14 20:19:06 -05:00
DrDoof 70f8964918 igmp: leave groups in 224.0.0.0/24 to flooding
The switch keeps flooding 224.0.0.0/24 with IGMP on, but a report for a
group in that block still made an entry for it, and the entry limited
the group to the ports that reported it. A host announcing mDNS on
224.0.0.251 thereby cut mDNS off from every other port. Such reports
are now ignored, as RFC 4541 asks.
2026-10-14 20:18:07 -05:00
DrDoof aba58e7f99 igmp: stop looking up IPv4 multicast in the L2 table on igmp off
igmp_setup(), which `igmp off` also calls, enabled the lookup of IPv4
multicast in the L2 table. Groups learned while IGMP was on therefore
kept going only to the ports that had reported them, and with reports
no longer trapped nothing updated those entries until a reboot.

The lookup is now enabled in igmp_enable() and disabled in igmp_setup(),
so with IGMP off all IP multicast is flooded again.
2026-10-14 20:18:07 -05:00
d00f 2404e7a9b6 lacp: tidy up after review
Move port_bit() to rtl837x_common.h as PORT_BIT(), a uint16_t shift,
and MAC_ADDR_LEN from rtl837x_lldp.h next to it, and use MAC_ADDR_LEN
for every address in the LACP code instead of a literal 6. Define
lacp_mux_update() before its first caller and drop the forward
declaration, declare variables at the top of their blocks, put the
operator at the end of a continued line, drop the field value comments
of the LACPDU struct, and leave lacp_port_lag to lacp_init() instead of
initialising it in the test environment.
2026-10-14 20:18:07 -05:00
d00f 6a31b4a279 doc: lacp: shorten, point to stp.md for the trap
The trap is described with STP, so the LACP page only says that it is
used. The LACP sections leave link_aggregation.md, which now points to
lacp.md, and the timing section gives the values in seconds and the
802.3ad requirements without the test history.
2026-10-14 20:18:07 -05:00
d00f 6cd1f683bb lacp: keep comments to the frame layout
The comments repeated the documentation, described tests or explained
the code to its author. What stays describes the LACPDU structures. The
timer constants are decimal, in units of the LACP timer.
2026-10-14 20:18:07 -05:00
d00f 7e90f6a126 test: build the LACP test on the real headers, drop the port_hash test
The LACP test now compiles with the shared harness flags and
sdcc_shim.h against the firmware headers, so the copies under
test/lacp/shim are gone. test_port_tables already covers the trunk hash
seed that test/port_hash checked against its own register copies.
lacp_in() declares its locals at the top, which the stricter host build
needs.
2026-10-14 20:18:07 -05:00
d00f 9bd301447b doc: lacp: lag <n> d and a static list leave LACP, new lacp_lag_set() prototype 2026-10-14 20:18:07 -05:00
d00f 9745dfe6ae lacp: drop the unused long timeout and an unrelated pvid hunk 2026-10-14 20:18:07 -05:00
d00f d4345c1bf8 lacp: keep lacp_in() and lacp_lag_set() out of the data segment
The port and group of lacp_in(), the member mask passed to
lacp_lag_set() and the compiler temporaries both functions spilled took
six bytes of DSEG, and with them six bytes of stack. The locals and the
mask live in xdata now, the partner fields go through the scratch word,
and lacp_lag_set() records the new group of a port before it releases
the old one. One byte is left: the group number passed in.
2026-10-14 20:18:07 -05:00
d00f fcaacd4429 lacp: review follow-ups
lacp_in() always leaves uip_len at 0, so the tcpip_output() after it
never ran. The LAG page names the active members by front-panel port
instead of a logical mask. The partner key is not part of selection;
say so under Known limits.
2026-10-14 20:18:07 -05:00
d00f 0f63244ca1 lacp: ignore a LACPDU that carries our own system id
Two ports of one group cabled to each other heard themselves and the
group aggregated with itself. Sandbox T24.
2026-10-14 20:18:07 -05:00
d00f 913e9780b8 httpd: leave the L2 listing as it is on main
Listing by next-address also returned the reserved-multicast entries STP
writes, shown as port 1 with a delete button, while l2_delete() still
looks up by next-unicast and so removed the unicast entry after that
index instead. The change was there to show the LACP steering entries;
delivery by trap writes none, so it goes.
2026-10-14 20:18:07 -05:00
d00f 0d748fa808 lacp: "lag <n> d" and a static member list take the group out of LACP
Both paths wrote the trunk registers directly and left the protocol
running on the group, so "lag show" said disabled while the partner kept
both links in one aggregate, and re-sending the LACP line did not repair
it because the same-ports shortcut returns early. Each path now releases
the group from LACP first; for a group that never ran LACP that is a
no-op.
2026-10-14 20:18:07 -05:00
d00f bd974e0aaf lacp: arm the partner timeout from our own LACP_Timeout
The receive machine armed current_while from the partner's TIMEOUT bit,
so against a partner on the slow rate a port whose LACPDUs stopped with
the link still up stayed in the trunk for the long timeout, two minutes.
802.3ad 43.4.12 starts the timer from the actor's own LACP_Timeout, and
we always advertise the short one: the partner sends every second and is
let go after the short timeout.

Sandbox T23 plays a slow-rate partner that goes quiet and fails on the
code before this.
2026-10-14 20:18:07 -05:00
DrDoof 56686185ce lacp: implement IEEE 802.3ad link aggregation
Dynamic link aggregation on top of the static LAGG, for RTL8372/8373:
receive, selection and mux state machines (coupled mux, one aggregator
per group), with "lacp show" to look inside. Each of the four trunk
groups runs its own aggregator on the candidate ports assigned with
"lag <n> lacp <ports>"; the engine starts with the first such group and
stops with the last.

LACPDUs reach the CPU through the reserved-multicast trap, so delivery
needs no L2 entry and nothing written per VLAN or per PVID. The trap
acts on the address before the VLAN lookup and before the ingress
filters, so a LACPDU also arrives on a port that admits tagged frames
only and on a port STP holds in blocking, neither of which a forwarded
one reaches. A trapped frame carries no VLAN tag,
so lacp_in() takes the offset of the PDU body from TRAP_RX_BODY(). The
action is set with trap_rma_set(), which leaves the flags sharing that
register alone, and "lacp off" puts the slow-protocols drop default
back. doc/lacp.md and doc/link_aggregation.md record what was measured,
including why the trap looked like a dead end at first.

The web UI gets a Static/LACP mode per group on the LAG page with live
status, and the startup-config validator knows the per-group syntax. A
host-side sandbox for the state machines runs in the test harness
together with the LAG hash check. It drives both forms of an incoming
LACPDU, so the body offset of a trapped one is covered as well.

The L2 table page iterated with the "next unicast" read method, so
static multicast entries such as an IGMP group were invisible. It now
iterates with "next address", skips L3 entries (their layout carries IP
addresses where a MAC is expected), and reports the lowest member of a
multicast entry's port mask, so such an entry shows up as a static
entry on that port.

A port taken out of LACP forgets its partner, so "lacp show" after
"lacp off" no longer reports one. Applying the same candidate set to a
group again, as the LAG page does on every Apply, leaves the trunk
alone instead of tearing it down for a second or two. lacp_in() checks
the frame length and ethertype before reading a LACPDU, so a runt or a
foreign frame on the slow-protocols address cannot leave stale buffer
bytes as a partner. The sandbox covers these three in T20-T22. On the
LAG page, LACP mode with no ports checked sends "lag N lacp off", and
the startup-config validator wants at least one port after "lacp".
2026-10-14 20:18:07 -05:00
HL Yi ed069b67fd update doc to match new split machine structure 2026-10-14 20:17:03 -05:00
d00f b1026490a8 doc: point the link aggregation entry at the document that exists
The document was renamed from doc/trunking.md in "Update LAG configuration
registers" and the entry in the README kept the old name, so it leads
nowhere.
2026-10-15 00:59:58 +02:00
HL Yi b096efd63a symlink HASIVO_S1100WP_8GT_1SX_SE.c to SWTGW218AS.c, FNS1200P.c to PCB_K0402WS_V2.c, DEFAULT_8C_1SFP.c to KP_9000_9XH_X_EU.c, as only differences are white space and comments. add SKS3200_8E1X 2026-10-13 23:48:28 -05:00
78 changed files with 1105 additions and 264 deletions

No files matched your search

+11
View File
@@ -4,6 +4,17 @@
## Added
- Devices
- Support the hongyavision HYWS-SGT0204S (PCB marking `2G5F4_10G2_V1.01`), an
RTL8372 based 4x2.5G + 2xSFP+ unmanaged switch with a 512 KB Bright Moon
`T25S40` flash. It is a sibling of the KP-9000-6XH-X2 (2M-PCB43-V1.1) with
the two SFP+ cages wired the other way round (physical 5 is on SDS1,
physical 6 on SDS0), no reset button fitted, wrong silkscreen labels on the
serial header, `LED_GLB_IO_EN` bit 6 has to be set for the port LEDs to
work, and the fitted T25S40 cannot be read in DIO mode on this board, so the
target selects single-IO flash reads (`flash_sio`). New machine target
`MACHINE_2G5F4_10G2_V1_01`, see `doc/devices/2G5F4_10G2_V1.01.md`.
- Web UI
- Compress the embedded assets (minify + gzip) and switch to a single-page layout. #315
- Replace the multi-page UI with a themed single-page app: light, dark and Selenized themes following the browser by default,
+1
View File
@@ -103,6 +103,7 @@ SRCS += \
rtl837x_flash.c \
rtl837x_igmp.c \
rtl837x_init.c \
rtl837x_nic.c \
rtl837x_leds.c \
rtl837x_leds_dump.c \
rtl837x_phy.c \
+2 -2
View File
@@ -191,7 +191,7 @@ Go to "Firmware update" tab, select the correct file.
> [!IMPORTANT]
> If your device already runs RTLPlayground, you must upload the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
> If your device is OEM, you must upload the binary file /RTLPlayground/installer/outputrtlplayground_oem_upgrade.bin
> If your device is OEM, you must upload the binary file /RTLPlayground/installer/output/rtlplayground_oem_upgrade.bin
> [!CAUTION]
> Check one more time that your device matches the machine type before flashing.
@@ -364,7 +364,7 @@ The following documents give further documentation on specific features of the R
- [L2 learning](doc/l2.md)
- [IGMP (IP-MC streaming)](doc/igmp.md)
- [SFP+ ports](doc/sfp.md)
- [Trunking aka. port aggregation](doc/trunking.md)
- [Trunking aka. port aggregation](doc/link_aggregation.md)
- [LACP (802.3ad link aggregation)](doc/lacp.md)
- [VLAN](doc/vlan.md)
- [Storm control](doc/storm_control.md)
+2 -1
View File
@@ -257,7 +257,7 @@ void nic_setup(void) __banked
// This sets the size of the RX buffer, the filling level is in 0x7874
// R7848-000004ff
REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff);
REG_SET(RTL837X_REG_NIC_RXBUFF_RX, RTL837X_NIC_RX_LAST_SLOT);
// R7844-000007fe
REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe);
@@ -296,6 +296,7 @@ void nic_setup(void) __banked
// Sequence number of TX packets
tx_seq = 0;
REG_SET(RTL837X_NIC_INT_MSK, NIC_INT_RXIE);
}
+1 -1
View File
@@ -745,7 +745,7 @@ void parse_isolate(void)
if (cmd_compare(2, "off")) {
for (uint8_t i = machine.min_port; i <= machine.max_port; i++)
members |= ((uint16_t)1) << i;
members |= 0x200; // CPU-port
members |= PMASK_CPU; // CPU-port
port_isolate(port_configured, members);
return;
}
+1 -1
View File
@@ -51,7 +51,7 @@ __xdata uip_ipaddr_t server;
#define DHCP_END 255
#pragma codeseg BANK3
#pragma constseg BANK2
#pragma constseg BANK3
struct dhcp_pkt {
uint8_t type;
+15
View File
@@ -34,6 +34,21 @@ Next, transfer the actual packet over by repeating the SFR function with a
pointer to the frame on the ASIC directly after the frame header and a
length as given by the length in the frame header + 7, again divided by 8.
The RX ring's inclusive last slot is configured as `0x4ff`, giving a byte
range of `0x0000` through `0x27ff`. If the descriptor occupies the last slot
at `0x27f8`, its payload starts at `0x0000`, not `0x2800`. The RX copy code
normalizes that starting address before DMA. It relies on the hardware to
wrap transfers that start inside the ring and cross its end, as observed
on SWTGW218AS. Programming an initial address of `0x2800` does not wrap
and can instead read zeros or stale TX data outside the RX ring.
Frame lengths are checked against `UIP_CONF_BUFFER_SIZE` before copying.
DMA works in whole eight-byte units. `UIP_CONF_BUFFER_ALLOC_SIZE` rounds
the backing storage up to the next complete word: 1,560 bytes for the
1,556-byte logical frame limit. This padding allows a maximum-size frame
to be transferred directly without a separate tail copy. The logical
frame limit and advertised MSS are unchanged.
The received frame will have an RTL proprietary Ethernet frame type of
0x8899 (RRPC) where normally the frame type 0x0800 for IPv4 would be located.
Further 6 bytes follow describing the frame, before the normal IPv4 data
+17
View File
@@ -177,3 +177,20 @@ Once the board has been tested on hardware:
`doc/devices/KP-9000-6XH-X2.md` and document which `MACHINE` to pick for
which silkscreen.
### Identifying the CPU variant
For RTL8373-based devices, use the read-only console command below to distinguish
the N and non-N CPU variants:
```text
regget 4
```
| Register 0x0004 value | CPU |
|---|---|
| `0x83730000` | RTL8373 (non-N) |
| `0x83737000` | RTL8373N |
Record the identified CPU in the device documentation. These values identify
only the CPU variant; document PHY and flash-chip models separately when verified.
+178
View File
@@ -0,0 +1,178 @@
hongyavision HYWS-SGT0204S
RTL8372-based 4×2.5G + 2×SFP+ unmanaged switch.
Also marked on the PCB as `2G5F4_10G2_V1.01`.
Stock firmware runs a factory test console on UART at 9600 baud 8N1 (banner
`RTL8371B start`, prompt `RTL8371B:`). There is no management CLI and no Web
interface.
Using SPI clamp in-board is the only method for initial installation and update.
Erase the whole chip and verify the write (`flashrom -v`) before powering the
board, so an incomplete write is caught before the board is powered up.
Stock flash chip is 512 KB (Bright Moon `T25S40`, 4 Mbit, SOP-8), which the
RTLPlayground image fills exactly.
### Label specifications
Case, top / front / nameplate:
<img src="photos/2G5F4_10G2_V1.01/assembled-top.jpg" width="300" />
<img src="photos/2G5F4_10G2_V1.01/assembled-front.jpg" width="300" />
<img src="photos/2G5F4_10G2_V1.01/assembled-bottom.jpg" width="300" />
- **Manufacturer**: hongyavision (Shenzhen Hongyavision Electronic Technology
Co., Ltd.)
- **Model**: HYWS-SGT0204S — the nameplate is printed in Chinese and reads
"10/100/1000/2500M fibre switch" and "4x 2.5G copper port + 2x 10G SFP+
optical port"
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1G / 2.5G / 10G
- **Power**: 12 V DC, 2 A
- **Serial number**: `S/N-YYYYMMDDNNNN`, e.g. `S/N-202312010028`
The top of the case only carries generic printing ("2.5G+10G High Speed Fiber
Transceiver / 4-Port 2.5G Ethernet Switch+10G Fiber"), so the nameplate on the
bottom is what identifies the device.
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP+ ports supporting 1G, 2.5G and 10G modules
- Copper LEDs: white (2.5G) and blue (link/activity)
- SFP LEDs: one single LED per port (link/activity)
- SFP EEPROM and DDM readable on both cages, verified with a 10G module
(`Rate: 0x67`, module identity and DDM values via the `sfp` console command)
- Serial console at 115200 8N1 (RTLPlayground) / 9600 8N1 (stock)
### Not verified
- The reset button footprint is unpopulated and the case has no opening for it,
so it could not be tested.
### PCB overview
**Board markings**
- Top silkscreen: `2G5F4_10G2_V1.01`
**Key components**
- Main switch: RTL8372 (RTL8371B family), reported as `RTL8372` (non-N) by
RTLPlayground. The chip sits under a heatsink and its package marking is not
readable.
- U1: SPI NOR flash, Bright Moon `T25S40`, 4 Mbit / 512 KB, SOP-8
- A 3-hole reset button footprint is present but unpopulated, and the case has
no opening for it, so there is no usable reset button
Top side:
<img src="photos/2G5F4_10G2_V1.01/pcb_top.jpg" width="600" />
Bottom:
<img src="photos/2G5F4_10G2_V1.01/pcb_bottom.jpg" width="600" />
The stock flash chip, Bright Moon `T25S40` (SOP-8, 4 Mbit / 512 KB):
<img src="photos/2G5F4_10G2_V1.01/flash_t25s40.jpg" width="300" />
### Port layout
| Front panel position | Logical port | Physical port | Type |
|----------------------|--------------|---------------|---------|
| SFP left | 8 | 5 | SFP+ |
| RJ45 1 | 4 | 1 | Copper |
| RJ45 2 | 5 | 2 | Copper |
| RJ45 3 | 6 | 3 | Copper |
| RJ45 4 | 7 | 4 | Copper |
| SFP right | 3 | 6 | SFP+ |
Copper ports 1–4 match the KP-9000-6XH-X2 (2M-PCB43-V1.1) layout, which this
board is a sibling of. The two SFP+ cages are wired the other way round
compared to that board: physical port 5 is on SDS1 and physical port 6 is on
SDS0.
### Serial console
The board has three through-holes used as the serial console, next to the
heatsink in the middle of the board and visible in the top side photo above (the
silkscreen labels are printed rotated by 90°). **The silkscreen labels are
wrong**: they are shifted relative to the actual signals.
| Silkscreen label | Actual signal |
|------------------|---------------|
| TX | GND |
| RX | TX |
| GND | RX |
Wiring (following the measured signals, not the labels):
| USB-TTL adapter | Board pad |
|-----------------|----------------------|
| GND | pad labelled `TX` |
| RX | pad labelled `RX` |
| TX | pad labelled `GND` |
- **Settings**: 115200 baud / 8N1 / 3.3V TTL (RTLPlayground), 9600 baud for the
stock firmware
- The stock firmware only prints a few bytes and a factory test menu
(`?`, `rst`, `f`, `r`, `10`, `100`, `g1`, `sd`, `eye`, …); it is not an
interactive management console
### LED configuration
Case silkscreen, below the RJ45 ports:
```
White : 2.5G Blue : 1000M/2500M L/A
```
The front panel also carries a `PWR` LED and one LED per SFP cage (`SFP1`,
`SFP2`) on the right hand side.
| Port | LED | Linked, idle | With traffic |
|------------|--------------|--------------|--------------|
| Copper | white | 2.5G only | same |
| Copper | blue | solid | blinks (L/A) |
| SFP | single LED | solid | blinks (L/A) |
Measured LED-ID mapping (from the RTL837x LED set registers):
| LED-ID | Function |
|--------|---------------------------------|
| LED-ID0| copper blue LED |
| LED-ID1| copper white LED |
| LED-ID2| SFP single LED |
**Important**: `RTL837X_REG_LED_GLB_IO_EN` bit 6 must be set in
`machine_custom_init()`. Without it the RTL837x "solid" conditions (LINK/speed)
do not drive the LEDs at all and only `ACT` does, which makes the white LED
glow faintly at non-2.5G speeds.
### SFP GPIO assignments
| SFP | pin\_detect (ModAbs) | pin\_los | SerDes | I2C SDA | I2C SCL |
|-------------------|-------------------------------|------------------|--------|-------------------------|--------------------------|
| Left (logical 8, physical 5) | GPIO30\_ACL\_BIT3\_EN | GPIO37 | SDS1 | GPIO39\_I2C\_SDA4 | GPIO40\_I2C\_SCL3\_MDC1 |
| Right (logical 3, physical 6)| GPIO50\_I2C\_SCL2\_UART1\_TX | GPIO10\_LED10 | SDS0 | GPIO41\_I2C\_SDA3\_MDIO1 | GPIO40\_I2C\_SCL3\_MDC1 |
`pin_tx_disable` is GPIO\_NA on both ports. Both I2C buses are confirmed
working: with the same 10G module inserted, the `sfp` console command reads its
vendor and model from the left cage (`Slot 1`) and from the right cage
(`Slot 2`), DDM values included. The insertion also shows which SerDes drives
each cage - the left cage reports `sds_config sds: 01` and the right cage
`sds: 00`, which matches the table above.
### Machine target
Build for this device with `make MACHINE=2G5F4_10G2_V1_01`, which selects the
`machine/2G5F4_10G2_V1_01.c` board definition. It is derived from
`machine/KP_9000_6XHML_X2.c` with the SFP cage order and the reset pin changed.
The fitted T25S40 cannot be read in DIO mode on this board: an image that leaves
DIO enabled does not come up at all, both at the default read clock divider of 4
and at 8 (two boards tested), while the same image with single-IO boots and runs
normally. The board definition therefore sets `flash_sio`, which makes
`flash_init()` use `CMD_FREAD` at divider 8. Only the management plane is
slower, the ASIC keeps forwarding in hardware.
+41
View File
@@ -0,0 +1,41 @@
# Hasivo S1100P-8GT-1SX-S
RTL8373N switch with 8 × 2.5G RJ45 ports and 1 × SFP port. GD25Q16 2 MiB flash.
## Port mapping
| Front port | ASIC MAC | Interface |
| --- | --- | --- |
| 1–8 | 0–7 | RJ45 |
| 9 | 8 | SFP (SDS1) |
## Board signals
| Function | GPIO |
| --- | --- |
| SFP detect | 38 |
| SFP LOS | 37 |
| SFP TX disable | Not connected (`GPIO_NA`) |
| SFP I2C SDA / SCL | 39 / 40 |
| Reset | 54 |
PoE is managed by an RTL8238B and a separate STC8H8K64U controller, not directly by the RTL8373N. RTLPlayground does not control PoE on this board.
## Build
`make MACHINE=HASIVO_S1100P_8GT_1SX_S CI=1`
## Photos
Front panel:
![Front panel](photos/Hasivo-S1100P-8GT-1SX-S/front.jpg)
PCB top:
![PCB top](photos/Hasivo-S1100P-8GT-1SX-S/pcb_top.jpg)
PCB bottom:
![PCB bottom](photos/Hasivo-S1100P-8GT-1SX-S/pcb_bottom.jpg)
+2
View File
@@ -90,6 +90,8 @@ Custom mapping for ONT-S207CW-62TS-SE:
## Flashing Instructions
See the [README.md](../../README.md) for general flashing instructions.
For compilation, use command `make MACHINE=ONT_S207CW_62TS_SE` to specify the machine.
If you are using managed version of the switch, you can then also compile the installer and flash using GUI - run command `cd installer` and finally `make`.
## Stock Firmware Information
+72
View File
@@ -0,0 +1,72 @@
# PCB-K0402WS-V1.0
This is the first revision of the PCB-K0402WS series of boards; it's very similar to 2.0 in terms of layout/wiring.
The board does have footprints for a VLAN modeswitch at the front and a second flash chip on the bottom of the PCB, but these have been seen to ship unpopulated.
### Brands
* YuanLey YS25-0402 <sup><sub>Note: there are [multiple revisions](PCB-K0402WS-V3.0.md) of the YS25-0402. This first revision lacks the "Vlan" switch cutout on the front of the enclosure.</sub></sup>
### Programming
Use a SOIC-8 clamp to the flash chip (U1 on silkscreen) at the top of the board, leaving it otherwise unpowered.
The board has been seen to ship with a single [BoyaMicro BY25Q16BSSIG](https://www.lcsc.com/datasheet/C382744.pdf) 16Mbit (2MiB) chip, though exact BOM may vary.
<a href="photos/PCB-K0402WS-V1.0/flash.jpg"><img src="photos/PCB-K0402WS-V1.0/flash.jpg" width="300" /></a>
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs (Power LED is always on)
### PCB overview
#### Board markings
- Top silkscreen: PCB-K0402W-V1.0 / DIP-K0402WS-V1.0
#### Key components
- U1: SPI NOR flash, 2 MiB
- S1: unpopulated slide switch footprint (three through-holes used as serial console)
Front panel
<a href="photos/PCB-K0402WS-V1.0/ports.jpg"><img src="photos/PCB-K0402WS-V1.0/ports.jpg" width="300" /></a>
PCB top
<a href="photos/PCB-K0402WS-V1.0/pcb-top.jpg"><img src="photos/PCB-K0402WS-V1.0/pcb-top.jpg" width="300" /></a>
PCB bottom
<a href="photos/PCB-K0402WS-V1.0/pcb-bottom.jpg"><img src="photos/PCB-K0402WS-V1.0/pcb-bottom.jpg" width="300" /></a>
Bottom and rear
<a href="photos/PCB-K0402WS-V1.0/bottom.jpg"><img src="photos/PCB-K0402WS-V1.0/bottom.jpg" width="300" /></a>
### Power supply
Input power is delivered via a standard DC barrel jack (5.5x2.1mm) with an included 12V 1A adapter.
There is an optional grounding screw next to the DC input.
### Serial console
The PCB has a slide switch footprint (unpopulated) at the front right that is connected to the UART. It is labeled as "S1" on the silkscreen.
Facing the top front (port) side of the board, the pinout from left to right is:
| Position | Signal | GPIO |
|----------|--------|-------------------|
| 1 | RX | GPIO32\_UART0\_RX |
| 2 | GND | N/A |
| 3 | TX | GPIO31\_UART0\_TX |
Standard 0.1" / 2.54mm pin headers will not fit, so wires or clips may be used instead.
The image below shows some oversized clips clumsily attached.
<a href="photos/PCB-K0402WS-V1.0/uart.jpg"><img src="photos/PCB-K0402WS-V1.0/uart.jpg" width="300" /></a>
+8 -3
View File
@@ -19,9 +19,14 @@ of the device just above the big label, might be covered by a QC sticker.
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402_label.jpg" width="300" />
* Siscolink SL-G0402F
* SICSOLINK SL-G0402F
<img src="photos/PCB-K0402WS-V3.0/SICSOLINK SL-G0402F.jpg" width="300"/>
* YuanLey YS25-0402 <sup><sub>Note: there are [multiple revisions](PCB-K0402WS-V1.0.md) of the YS25-0402. This is the newer revision that has a "Vlan" switch on the front.</sub></sup>
<img src="photos/PCB-K0402WS-V3.0/YuanLey_YS25-0402.jpg" width="300"/>
<img src="photos/PCB-K0402WS-V3.0/Siscolink SL-G0402F.jpg" width="300"/>
### Programming
Using SPI clamp in-board is the only method for initial installation.
@@ -43,7 +48,7 @@ For the initial flash (at least with flashrom), the bin file produced by the bui
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
- Top silkscreen: PCB-K0402W-V3.0 / DIP-K0402WS-V3.0
Top side
+32
View File
@@ -0,0 +1,32 @@
### SIRIVISION_S25G2206FP_V1_1
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| YuanLey | YS25-0402M | Yes | SIRIVISION_S25G2206FP_V1_1 | 2M | 8372 |
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
- **Power**: 12V DC, 1A 5525 connector
### What works
The device is fully supported:
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- ALL SFP+ ports support 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: SIRIVISION S25G2206FP V1.1
Top side
<img src="photos/SIRIVISION_S25G2206FP_V1_1/dev_pcb_top.jpg" width="300" />
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
+3 -2
View File
@@ -4,7 +4,8 @@
|---------|------------------|-------|------------------|-----------------|---------------|
| Ampcom | SWTG018AS-A V2.0 | No | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
| Horaco | HC-SWTGW218AS-A | Yes | SWTG018AS-A V2.0 | 2MB(25Q16JVSIQ) | 8273N + 8224N |
| GoodTop | GT-ST018M | Yes | SWTG018AS-A V2.0 | ? | 8273N + 8224N |
| GoodTop | GT-ST018M | Yes | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
| MokerLink | 2G08110GSN | No | SWTG018AS-A V2.0 | 512KB(25Q40) | 8273N + 8224N |
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
@@ -14,7 +15,7 @@ The original software is running UART on 9600 baud rate.
Using a SOIC clamp in-board is the only method for initial installation.
The board has a single flash chips `BS` with 4M-bit size. The front switch, switches between the two flash chips.
The board has a single flash chips `BS` with 2M-byte size. The front switch, switches between the two flash chips.
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
### Label specifications
+5 -4
View File
@@ -2,10 +2,11 @@
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| Horaco | ZX-SG4T2 | | PCB-SWTG024AS-A-V2.0.1_19650 | P25D40SH | ??? |
| GoodTop | GT-ST024M | Yes | PCB-SWTG024AS-A-V2.0.1 | 2M | ??? |
|Brand |Type |Managed|PCB |Flash |Chip RTL|
|---------|--------------|-------|------------------------------|----------------|--------|
| Horaco | ZX-SG4T2 | No | PCB-SWTG024AS-A-V2.0.1_19650 | 512K (P25D40SH)| 8372N |
| Horaco | HC-SWTG124AS | Yes | PCB-SWTG024AS-A-V2.0.1 | 2M (W25Q16JV)| 8372N |
| GoodTop | GT-ST024M | Yes | PCB-SWTG024AS-A-V2.0.1 | 2M | 8372N |
### Label specifications
+1 -1
View File
@@ -46,4 +46,4 @@ Note,`R52`、`R53`may not be installed.You need to bridge them using either sold
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
Input power is delivered via barell plug, `12V 1A` adapter was provided.
+7 -1
View File
@@ -5,9 +5,15 @@
|---|---|---|---|---|---|
| Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N |
| Sodola | | | | | |
| Horaco | | | | | |
| Horaco | HC-SWTGW218AS | Yes | SWTG118AS-V2.1 | 2MB | 8373 (non-N) |
| XikeStor | SKS3200-8E1X | Yes | SWTG118AS-V2.1-17462 | 2MB (25Q16JVSIQ) | |
All boards in this table use `MACHINE=SWTGW218AS`. The Horaco HC-SWTGW218AS is also sold with the
[SWTG018AS-A V2.0](SWTG018AS_A_V2_0.md) board, which needs a different firmware. Check the marking
on the PCB before flashing.
The PHY and flash-chip models for the tested Horaco units remain unverified.
## Photos
Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

+21 -14
View File
@@ -4,45 +4,52 @@ The following devices have been tested and are fully working:
| Brand | Type | Managed | PCB | Flash | Ports |
|----------|-----------------|---------|---------------------------------------------------------------------------|-------|-------|
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
| Binardat | 2G06-04210GSM | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
| Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 |
| FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 |
| Goalake | IG108 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
| GoodTop | GT-ST018M | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | ? | 8 + 1 |
| GoodTop | GT-ST024M | Yes | [SWTG024AS-A V2.0.1](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 2M | 4 + 2 |
| GoodTop | GT-ST018M | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | 2M | 8 + 1 |
| GoodTop | GT-ST024M | Yes | [SWTG024AS-A V2.0.1](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 2M | 4 + 2 |
| Guangnianwei | 7018-2.5G | No | [F7008-2.5GPOE-V1.2](devices/F7008-2.5.md) | 8M | 8 + 1 |
| Hasivo | S1100WP_8GT_1SX_SE | Yes | [S1100WP_8GT_1SX_SE-V1.05](devices/HASIVO_S1100WP_8GT_1SX_SE.md) | 2M | 8 + 1 |
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V2.0](devices/PCB-K0402WS-V2.0.md) | 2M | 4 + 2 |
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
| hongyavision | HYWS-SGT0204S | No | [2G5F4_10G2_V1.01](devices/2G5F4_10G2_V1.01.md) | 0.5M | 4 + 2 |
| hongyavision | LG-SG5T1 | No | [PCB-SWTG024AS-V2.0_16895](devices/SWTG024AS-V2.0.md) | 0.5M | 5 + 1 |
| Horaco | HC-SWTG124AS | Yes | [SWTG024AS-A-V2.0.1](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 2M | 4 + 2 |
| Horaco | HC-SWTGW215AS | Yes | [SWTG024AS-A-V2.0.1_19650 5C 1SFP](devices/SWTG024AS-A-V2.0.1_5C_1SFP.md) | ? | 5 + 1 |
| Horaco | HC-SWTGW218AS | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
| Horaco | HC-SWTGW218AS | Yes | [SWTG118AS-V2.1](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| Horaco | ZX310S-4T2XH | Yes | [PCB-SL310S-4T1T1X-V1.0.1-24107](devices/ZX310S-4T2XH.md) | 2M | 5 + 1 |
| Horaco | ZX310S-4T2XT | Yes | [PCB-SL310S-4T2XT-V1.0.0-22273](devices/ZX310S-4T2XT.md) | 2M | 6 |
| Horaco | ZX-SG4T2 | No | [SWTG024AS-A-V2.0.1_19650_4C_2SFP](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 0.5M | 4 + 2 |
| Horaco | ZX-SWTG124AS | Yes | [SWTG024AS-v2.0](devices/SWTG024AS.md) | | 4 + 2 |
| Keeplink | KP-9000-6XH-X2 / KP-9000-6XHML-X2 | No/Yes | [2M-PCB43-V1.2 / V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 |
| keepLINK | KP-9000-6XH-X2 / KP-9000-6XHML-X2 | No/Yes | [2M-PCB43-V1.2 / V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 |
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V2.2](devices/2M-PCB23-V2_2.md) | 2M | 8 + 1 |
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.2](devices/2M-PCB23-V3_2.md) | 2M | 8 + 1 |
| LIANGUO | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
| Lianguo | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| LIANGUO | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
| MokerLink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
| Binardat | 2G06-04210GSM | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
| ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
| MokerLink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| MokerLink| 2G08110GSN | No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | 0.5M | 8 + 1 |
| Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
| ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
| SICSOLINK| SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
| Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 |
| Steamemo | IG204-V1 | No | [PB-2131](devices/STEAMEMO_IG204_V1.md) | | 4 + 2 |
| TrendNet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 |
| Xikestore| SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
| TRENDnet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 |
| XikeStor | SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| YuanLey | YS25-0402 | No | [PCB-K0402WS-V1.0](devices/PCB-K0402WS-V1.0.md) | 2M | 4 + 2 |
| YuanLey | YS25-0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | 2M | 4 + 2 |
| YuanLey | YS25-0402M | Yes | [SIRIVISION_S25G2206FP_V1_1](devices/SIRIVISION_S25G2206FP_V1_1.md) | 2M | 4 + 2 |
| Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
| Guangnianwei | 7018-2.5G | No | [F7008-2.5GPOE-V1.2](devices/F7008-2.5.md) | 8M | 8 + 1 |
For KP-9000-6XH-X2 / KP-9000-6XHML-X2 / Mokerlink 2G040210GSM devices, select
the machine target by PCB revision. The ML/non-ML or managed/unmanaged label
+6
View File
@@ -64,6 +64,12 @@ struct machine {
uint8_t led_mux_custom;
uint8_t led_mux[28];
uint32_t mac_flash_offset;
// Read the flash with single-IO (CMD_FREAD) instead of DIO for MMIO/code
// fetch. Set for boards whose flash chip is not usable in DIO mode, which
// shows up as a board that does not boot at all, garbled console output or
// random resets. Costs management-plane speed only, the ASIC keeps
// forwarding in hardware.
uint8_t flash_sio;
};
struct machine_runtime
+1
View File
@@ -0,0 +1 @@
SWTG018AS_A_V_2_0.c
+6
View File
@@ -0,0 +1,6 @@
#ifndef _MACHINE_2G08110GSN_H_
#define _MACHINE_2G08110GSN_H_
#define MACHINE_MODEL "MokerLink 2G08110GSN"
#endif
+54
View File
@@ -0,0 +1,54 @@
#include "machine_defs.h"
__code const struct machine machine = {
.machine_name = MACHINE_MODEL,
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
/* Same 2M-PCB43-V1.1 board family as the KP-9000-6XH-X2 (see
* machine/KP_9000_6XHML_X2.c), but the two SFP+ cages (physical ports 5 and
* 6) are wired the other way round: physical 5 is on SDS1, physical 6 on
* SDS0. Copper ports 1-4 match the KP-9000 layout. */
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
// Left SFP cage (physical port 5) = SDS1
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
// Right SFP cage (physical port 6) = SDS0
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_los = GPIO10_LED10,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
/* The board has a 3-hole reset button footprint, but it is unpopulated and
* the case has no opening for it, so reset_pin stays GPIO_NA. GPIO54, the
* reset pin on the KP-9000 layout, reads as permanently pressed here. */
.reset_pin = GPIO_NA,
/* The fitted T25S40 does not work in DIO mode on this board, so read the flash
* with single-IO; see doc/devices/2G5F4_10G2_V1.01.md. */
.flash_sio = 1,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
/* Conditions for LED on:
* dual led orange: ledset_0 & ledset_2
* dual led green: ledset_2 & !ledset_0
* single right led green: ledset_0 & !ledset_1
*
* Measured on this board: LED-ID0 is the copper blue LED, LED-ID1 the
* copper white one (setting LED-ID0 to 0 killed blue while leaving white on
* at 2.5G only) and LED-ID2 carries the SFP single LED. The "solid"
* conditions (LINK/speed) barely drive the LEDs here and ACT is what
* actually lights them, which is why the white LED used to glow faintly at
* non-2.5G speeds; the fix for that is LED_GLB_IO_EN bit 6, set in
* machine_init.c. */
.led_sets = { { LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
LEDS_2G5 | LEDS_LINK | LEDS_10G,
LEDS_1G | LEDS_LINK,
0 },
},
};
+6
View File
@@ -0,0 +1,6 @@
#ifndef _MACHINE_2G5F4_10G2_V1_01_H_
#define _MACHINE_2G5F4_10G2_V1_01_H_
#define MACHINE_MODEL "2G5F4_10G2_V1.01 / SGT0204S"
#endif
-25
View File
@@ -1,25 +0,0 @@
#include "machine_defs.h"
__code const struct machine machine = {
.machine_name = MACHINE_MODEL,
.isRTL8373 = 1,
.min_port = 0,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
.led_sets = { { LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
LEDS_2G5 | LEDS_LINK,
LEDS_1G | LEDS_LINK,
LEDS_2G5 | LEDS_LINK | LEDS_ACT },
},
};
+1
View File
@@ -0,0 +1 @@
KP_9000_9XH_X_EU.c
-55
View File
@@ -1,55 +0,0 @@
#include "machine_defs.h"
__code const struct machine machine = {
.machine_name = MACHINE_MODEL,
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
/* Left SFP (logical 8, SDS1): GPIO30=ModAbs, GPIO37=RX_LOS */
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
/* Right SFP (logical 3, SDS0): GPIO50=ModAbs, GPIO51=RX_LOS */
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
/* Copper ports use SET0; SFP ports use SET1 */
.port_led_set = {0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{ /* SET0: copper — LED0=amber (2.5G), LED2=green (1G/100M/10M) */
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0
},
{ /* SET1: SFP — all speeds link/act */
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0, 0
},
},
.led_mux_custom = 1,
.led_mux = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* GPIO0-7: unused */
0x0f, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, /* GPIO8-14 */
0x14, 0x15, 0x16, 0x18, 0x19, 0x1a, /* GPIO15-20 */
0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x23 /* GPIO21-27 */
},
};
+1
View File
@@ -0,0 +1 @@
PCB_K0402WS_V2.c
+1
View File
@@ -0,0 +1 @@
SWTG018AS_A_V_2_0.c
+6
View File
@@ -0,0 +1,6 @@
#ifndef _MACHINE_GT_ST018M_H_
#define _MACHINE_GT_ST018M_H_
#define MACHINE_MODEL "GoodTop GT-ST018M"
#endif
+40
View File
@@ -0,0 +1,40 @@
#include "machine_defs.h"
__code const struct machine machine = {
.machine_name = MACHINE_MODEL,
.isRTL8373 = 1,
.mac_flash_offset = 0x1FC000,
.min_port = 0,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO38,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = {
{
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // LED0: orange
0,
LEDS_2G5 | LEDS_LINK | LEDS_ACT, // LED2: green
0
},
{
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT, // SFP LED0: green (both SFP LEDs are green)
0, 0, 0
}
},
.led_mux_custom = 1,
.led_mux = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x09,
0x0e, 0x10, 0x12, 0x0e, 0x14, 0x11, 0x12, 0x16,
0x15, 0x16, 0x18, 0x19, 0x1a, 0x1a, 0x1d, 0x1e,
0x1c, 0x1e, 0x20, 0x21
},
};
+6
View File
@@ -0,0 +1,6 @@
#ifndef _MACHINE_HASIVO_S1100P_8GT_1SX_S_H_
#define _MACHINE_HASIVO_S1100P_8GT_1SX_S_H_
#define MACHINE_MODEL "Hasivo S1100P-8GT-1SX-S"
#endif
-32
View File
@@ -1,32 +0,0 @@
#include "machine_defs.h"
__code const struct machine machine = {
.machine_name = MACHINE_MODEL,
.isRTL8373 = 1,
.mac_flash_offset = 0x1FC000,
.min_port = 0,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green LED (right)
0,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber LED (left)
0
},
{ LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT, // SFP LED
0,
0,
0
},
},
};
+1
View File
@@ -0,0 +1 @@
SWTGW218AS.c
+1
View File
@@ -0,0 +1 @@
PCB_SWTG024AS_A_2_0_1.c
+6
View File
@@ -0,0 +1,6 @@
#ifndef _MACHINE_HC_SWTG124AS_H_
#define _MACHINE_HC_SWTG124AS_H_
#define MACHINE_MODEL "Horaco HC-SWTG124AS"
#endif
+57
View File
@@ -0,0 +1,57 @@
#include "machine_defs.h"
__code const struct machine machine = {
.machine_name = MACHINE_MODEL,
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
/* Left SFP (logical 8, SDS1): GPIO30=ModAbs, GPIO37=RX_LOS */
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
/* Right SFP (logical 3, SDS0): GPIO50=ModAbs, GPIO51=RX_LOS */
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
.reset_pin = GPIO_NA,
/* These don't appear to be populated / wired-up; the power LED is always on */
.high_leds = { 0 },
/* Copper ports use SET0; SFP ports use SET1 */
.port_led_set = {0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{ /* SET0: copper — LED0=amber (2.5G), LED2=green (1G/100M/10M) */
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0
},
{ /* SET1: SFP — all speeds link/act */
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
0
},
},
.led_mux_custom = 1,
.led_mux = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* GPIO0-7: unused */
0x0f, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, /* GPIO8-14 */
0x14, 0x15, 0x16, 0x18, 0x19, 0x1a, /* GPIO15-20 */
0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x23 /* GPIO21-27 */
},
};
+6
View File
@@ -0,0 +1,6 @@
#ifndef _MACHINE_PCB_K0402WS_V1_H_
#define _MACHINE_PCB_K0402WS_V1_H_
#define MACHINE_MODEL "PCB-K0402WS-V1.0"
#endif
+1 -1
View File
@@ -1,7 +1,7 @@
#include "machine_defs.h"
__code const struct machine machine = {
.machine_name = MACHINE_MODEL,
.machine_name = MACHINE_MODEL,
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
+41
View File
@@ -0,0 +1,41 @@
#include "machine_defs.h"
__code const struct machine machine = {
.machine_name = MACHINE_MODEL,
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp= {0, 0, 0, 2, 0, 0, 0, 0, 1},
// Left SFP port (J4)
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 39 */
// Right SFP port (J2)
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 40 */
.reset_pin = GPIO36_PWM_OUT,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{ /* RJ45: Green LED */
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
0,
/* Amber LED */
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0
}, { /* SFP PORT: SINGLE GREEN LED */
LEDS_10M | LEDS_100M | LEDS_1G | LEDS_2G5 | LEDS_10G | LEDS_LINK | LEDS_ACT,
0,
0,
0,
},
},
};
+6
View File
@@ -0,0 +1,6 @@
#ifndef _MACHINE_SIRIVISION_S25G2206FP_V1_1_H_
#define _MACHINE_SIRIVISION_S25G2206FP_V1_1_H_
#define MACHINE_MODEL "SIRIVISION S25G2206FP V1.1"
#endif
+1
View File
@@ -0,0 +1 @@
PCB_SWTG018AS_V2_1_0.c
+7
View File
@@ -0,0 +1,7 @@
#ifndef _MACHINE_SKS3200_8E1X_H_
#define _MACHINE_SKS3200_8E1X_H_
#define MACHINE_MODEL "XikeStor SKS3200-8E1X"
#endif
+1
View File
@@ -0,0 +1 @@
SIRIVISION_S25G2206FP_V1_1.c
+6
View File
@@ -0,0 +1,6 @@
#ifndef _MACHINE_YS25_0402M_H_
#define _MACHINE_YS25_0402M_H_
#define MACHINE_MODEL "YuanLey YS25-0402M"
#endif
+1
View File
@@ -19,6 +19,7 @@
defined(MACHINE_HI_K0402WS) || \
defined(MACHINE_PCB_K0402WS_V2) || \
defined(MACHINE_PCB_K0402WS_V3) || \
defined(MACHINE_2G5F4_10G2_V1_01) || \
defined(MACHINE_FNS1200P)
void machine_custom_init(void) __banked
{
+2 -2
View File
@@ -23,7 +23,7 @@
// Define Port-masks for 9-port devices and 6-port devices
#define PMASK_9 0x1ff
#define PMASK_6 0x1f8
#define PMASK_CPU 0x200
#define PMASK_CPU ((uint16_t)(1 << CPU_PORT))
// Defines a port mask for dropping all packets on Lookup-miss
#define LOOKUP_MISS_DROP_6 0x00015540
@@ -142,7 +142,7 @@ extern __xdata bool stp_enabled;
* advertises it as the System Name TLV) read it from here. */
extern __xdata char hostname[24];
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE];
extern __xdata struct uip_eth_addr uip_ethaddr;
// Headers for calls in the common code area (HOME/BANK0)
+1 -1
View File
@@ -28,7 +28,7 @@ extern __xdata uint8_t igmpEnabled;
extern __xdata uint8_t cpuPort;
extern __xdata uint8_t sfr_data[4];
extern __xdata struct machine_runtime machine_detected;
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE];
__xdata uint16_t idx;
#define IGMP_IP_HDR offsetof(struct igmp_pkt, hlen)
+1 -1
View File
@@ -21,7 +21,7 @@ extern __code const struct machine machine;
extern __xdata struct machine_runtime machine_detected;
extern __xdata uint16_t management_vlan;
extern __xdata struct uip_eth_addr uip_ethaddr;
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE];
/* 20-byte Actor/Partner information body (802.3ad 43.4.2.2), network byte order */
struct lacp_info {
+90
View File
@@ -0,0 +1,90 @@
#include "rtl837x_common.h"
#include "rtl837x_regs.h"
#include "rtl837x_sfr.h"
#include "rtl837x_nic.h"
extern __xdata uint8_t rx_headers[16];
#ifndef RTLP_HOST_TEST
/* One RX DMA operation, starting inside the configured ring. The hardware
* wraps transfers that cross its end; the initial address must be normalized.
* Host tests supply a simulated DMA engine for this hardware boundary. */
bool nic_rx_dma(__xdata uint8_t *buffer, uint16_t ring_ptr, uint8_t words) __reentrant
{
uint16_t guard = 0;
SFR_NIC_DATA_U16LE = (uint16_t)buffer;
SFR_NIC_RING_U16LE = ring_ptr;
SFR_NIC_CTRL = words;
while (SFR_NIC_CTRL != 0) {
if (++guard == 0) {
print_string("NIC: RX transfer did not complete\n");
return false;
}
}
return true;
}
#endif
static bool nic_rx_copy(__xdata uint8_t *buffer, uint16_t ring_ptr, uint8_t words) __reentrant
{
if (ring_ptr > RTL837X_NIC_RX_RING_BYTES || (ring_ptr & 7))
return false;
if (ring_ptr == RTL837X_NIC_RX_RING_BYTES)
ring_ptr = 0;
return nic_rx_dma(buffer, ring_ptr, words);
}
bool nic_rx_header(uint16_t ring_ptr) __reentrant
{
if (ring_ptr >= RTL837X_NIC_RX_RING_BYTES)
return false;
return nic_rx_copy(rx_headers, ring_ptr, 1);
}
bool nic_rx_packet(__xdata uint8_t *buffer, uint16_t ring_ptr) __reentrant
{
uint16_t len = ((uint16_t)rx_headers[5] << 8) | rx_headers[4];
if (!len || len > UIP_CONF_BUFFER_SIZE)
return false;
return nic_rx_copy(buffer, ring_ptr, (len + 7) >> 3);
}
/*
* Transfers data in XMEM to the ASIC for transmission by the NIC
*/
void nic_tx_packet(__xdata uint8_t *buffer, uint16_t len, uint16_t ring_ptr)
{
uint16_t guard = 0;
SFR_NIC_DATA_U16LE = (uint16_t)(uintptr_t)buffer;
#ifdef RXTXDBG
print_string("TX: \n");
for (uint8_t i = 0; i < 100; i++) {
print_byte(uip_buf[i]);
write_char(' ');
}
write_char('\n');
#endif
ring_ptr <<= 3;
ring_ptr |= 0x8000;
SFR_NIC_RING_U16LE = ring_ptr;
len += 0xf;
len >>= 3;
SFR_NIC_CTRL = len;
while (SFR_NIC_CTRL != 0) {
if (++guard == 0) {
print_string("NIC: TX transfer did not complete\n");
return;
}
}
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef RTL837X_NIC_H
#define RTL837X_NIC_H
#include <stdbool.h>
#include <stdint.h>
// #define RXTXDBG 1
bool nic_rx_header(uint16_t ring_ptr) __reentrant;
bool nic_rx_packet(__xdata uint8_t *buffer, uint16_t ring_ptr) __reentrant;
/* buffer starts at the eight-byte NIC descriptor; len excludes that
* descriptor. ring_ptr is the ASIC TX position in eight-byte slots. */
void nic_tx_packet(__xdata uint8_t *buffer, uint16_t len, uint16_t ring_ptr);
/* RX DMA in eight-byte units. ring_ptr must start inside the configured
* RX ring; the hardware wraps transfers that cross its end. */
bool nic_rx_dma(__xdata uint8_t *buffer, uint16_t ring_ptr, uint8_t words) __reentrant;
#endif
+1 -1
View File
@@ -57,7 +57,7 @@ void port_mirror_del(void) __banked
bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked
{
if (port > 9 || type >= VLAN_INVALID) {
if (port > CPU_PORT || type >= VLAN_INVALID) {
print_string("Invalid port or ingress filter type\n");
return false;
}
+3
View File
@@ -147,6 +147,9 @@
*/
#define RTL837X_REG_NIC_BUFFSIZE_TX 0x7844
#define RTL837X_REG_NIC_RXBUFF_RX 0x7848
/* RX ring: inclusive final eight-byte slot, as programmed by nic_setup(). */
#define RTL837X_NIC_RX_LAST_SLOT 0x04ff
#define RTL837X_NIC_RX_RING_BYTES ((RTL837X_NIC_RX_LAST_SLOT + 1U) * 8U)
#define RTL837X_REG_NIC_RXCMD 0x784c
#define RTL837X_REG_NIC_TXCMD 0x7850
#define RTL837X_REG_RX_CTRL 0x785c
+1 -1
View File
@@ -30,7 +30,7 @@ extern __xdata struct machine_runtime machine_detected;
extern __xdata struct uip_eth_addr uip_ethaddr;
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE];
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
extern __xdata uint8_t cmd_words_len;
+1 -1
View File
@@ -46,7 +46,7 @@ extern __xdata uint8_t stp_pflags[STP_ENTITIES];
extern __xdata uint32_t stp_pcost[STP_ENTITIES]; /* path cost; 0 = auto (20000) */
extern __xdata uint8_t stp_pprio[STP_ENTITIES];
extern __xdata uint8_t stp_pp2p[STP_ENTITIES];
extern __xdata uint8_t stp_ent_of[10]; /* the STP entity a port answers to: itself, or its lag */
extern __xdata uint8_t stp_ent_of[STP_PORTS]; /* the STP entity a port answers to: itself, or its lag */
extern __xdata uint16_t stp_lag_mask[STP_LAG_COUNT]; /* member ports of each lag; 0 = not part of STP */
/* Last-heard designated info per port (from received BPDUs); consult
+11 -110
View File
@@ -2,7 +2,6 @@
#include <stdint.h>
// #define REGDBG 1
// #define RXTXDBG 1
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h"
@@ -12,6 +11,7 @@
#include "rtl837x_phy.h"
#include "rtl837x_port.h"
#include "rtl837x_trap.h"
#include "rtl837x_nic.h"
#include "rtl837x_stp.h"
#include "rtl837x_lacp.h"
#include "rtl837x_igmp.h"
@@ -123,8 +123,8 @@ __code const uint8_t * __code const hex = "0123456789abcdef";
__xdata uint8_t flash_buf[FLASH_BUF_SIZE];
// NIC buffers for packet RX/TX
__xdata uint8_t rx_headers[16]; // Packet header(s) on RX
__xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
__xdata uint8_t rx_headers[16]; // RX descriptor
__xdata uint8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE];
__xdata uint16_t rx_packet_vlan;
__xdata uint16_t management_vlan;
@@ -714,108 +714,6 @@ void get_random_32(void)
}
/*
* Transfer Network Interface RX data from the ASIC to the 8051 XMEM
* data will be stored in the rx_header structure
* len is the length of data to be transferred
*/
bool nic_rx_header(uint16_t ring_ptr)
{
uint16_t buffer = (uint16_t) &rx_headers[0];
uint16_t guard = 0;
SFR_NIC_DATA_U16LE = buffer;
SFR_NIC_RING_U16LE = ring_ptr;
SFR_NIC_CTRL = 1;
while (SFR_NIC_CTRL != 0) {
if (++guard == 0) {
print_string("NIC: RX header transfer did not complete\n");
return false;
}
}
return true;
}
/*
* Transfer Network Interface RX data from the ASIC to the 8051 XMEM
* the description of the packet must be in the rx_headers data structure
* data will be returned in the xmem buffer points to
* ring_ptr is the current position of the RX Ring on the ASIC side
*/
bool nic_rx_packet(uint16_t buffer, uint16_t ring_ptr)
{
uint16_t guard = 0;
SFR_NIC_DATA_U16LE = buffer;
SFR_NIC_RING_U16LE = ring_ptr;
uint16_t len = (((uint16_t)rx_headers[5]) << 8) | rx_headers[4];
len += 7;
len >>= 3;
#ifdef RXTXDBG
print_string(" len: ");
print_short(len);
#endif
SFR_NIC_CTRL = len;
while (SFR_NIC_CTRL != 0) {
if (++guard == 0) {
print_string("NIC: RX transfer did not complete\n");
return false;
}
}
return true;
}
/*
* Transfers data in XMEM to the ASIC for transmission by the nic
*/
void nic_tx_packet(uint16_t ring_ptr)
{
uint16_t len;
uint16_t guard = 0;
/* A frame that got a dot1Q tag was shifted forward over its padding, so it
* starts at uip_buf and carries the q_frame layout. One that did not keeps
* the padding in front and the nonq_frame layout, so the padding is skipped.
*/
if (frame_tagged) {
SFR_NIC_DATA_U16LE = (uint16_t) uip_buf;
len = FRAME_Q->len;
/*
(__xdata struct rtl_dot1q_frame *)uip_buf
#define FRAME (((__xdata struct rtl_dot1q_frame *)&uip_buf[0]).nonq_frame)*/
} else {
SFR_NIC_DATA_U16LE = (uint16_t) uip_buf + VLAN_TAG_SIZE;
len = FRAME->len;
}
#ifdef RXTXDBG
print_string("TX: \n");
for (uint8_t i = 0; i < 100; i++) {
print_byte(uip_buf[i]);
write_char(' ');
}
write_char('\n');
#endif
ring_ptr <<= 3;
ring_ptr |= 0x8000;
SFR_NIC_RING_U16LE = ring_ptr;
len += 0xf;
len >>= 3;
SFR_NIC_CTRL = len;
while (SFR_NIC_CTRL != 0) {
if (++guard == 0) {
print_string("NIC: TX transfer did not complete\n");
return;
}
}
}
/* Read flash using the MMIO capabilities of the DW8051 core
* Bank is < 0x3f and is the MSB
* addr gives the address in the bank
@@ -999,8 +897,12 @@ void tcpip_output(void)
uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8;
ring_ptr |= sfr_data[3];
// Move data over from xmem buffer to ASIC side using DMA
nic_tx_packet(ring_ptr);
// Move data over from xmem buffer to ASIC side using DMA. A VLAN-tagged
// frame starts at uip_buf; an untagged frame retains four bytes of padding.
if (frame_tagged)
nic_tx_packet(uip_buf, FRAME_Q->len, ring_ptr);
else
nic_tx_packet(uip_buf + VLAN_TAG_SIZE, FRAME->len, ring_ptr);
// New position of the ring-pointer on the NIC-side indicates number of bytes transmitted
reg_read_m(RTL837X_REG_NIC_TX_CURR_PKT);
@@ -1037,7 +939,7 @@ void handle_rx(void)
write_char(' ');
}
#endif
if (!nic_rx_packet((uint16_t) &uip_buf[0], ring_ptr + 8)) {
if (!nic_rx_packet(uip_buf, ring_ptr + 8)) {
REG_SET(RTL837X_REG_NIC_RXCMD, 1);
return;
}
@@ -1684,7 +1586,7 @@ void main(void)
// Flash controller should be initialized before any code in other banks is being fetched
// See this issue: https://github.com/logicog/RTLPlayground/issues/70
print_string("\nInitializing Flash controller\n");
flash_init(1);
flash_init(machine.flash_sio ? 0 : 1);
// Set default for SFP pins so we can start up a module already inserted
sfp_pins_last = 0x33; // signal LOS and no module inserted (for both slots, even if only 1 present)
@@ -1805,7 +1707,6 @@ void main(void)
lacpEnabled = 0;
lacp_init();
nic_setup();
REG_SET(RTL837X_NIC_INT_MSK, NIC_INT_RXIE);
trap_init();
vlan_setup();
port_l2_setup();
+6
View File
@@ -29,6 +29,7 @@ TESTS = $(BUILDDIR)/test_cmd_editor \
$(BUILDDIR)/test_page_json \
$(BUILDDIR)/test_httpd_tx \
$(BUILDDIR)/test_tick_gate \
$(BUILDDIR)/test_nic_rx \
$(BUILDDIR)/test_lacp
# The table tests link the register mock and one environment file; stub/
@@ -52,6 +53,11 @@ $(BUILDDIR)/test_port_tables: test_port_tables.c $(TABLE_ENV) hw_mock.h | $(BUIL
$(BUILDDIR)/test_tick_gate: test_tick_gate.c support.c $(SRCROOT)/cmd_editor.c | $(BUILDDIR)
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
# Exercise the production RX ring reader; only the hardware DMA edge is mocked.
# Discard unused TX functions so this RX fixture needs no TX register mocks.
$(BUILDDIR)/test_nic_rx: test_nic_rx.c $(SRCROOT)/rtl837x_nic.c $(SRCROOT)/rtl837x_nic.h | $(BUILDDIR)
$(CC) $(CFLAGS) -ffunction-sections -fdata-sections $(filter %.c,$^) -o $@ $(LDFLAGS) -Wl,--gc-sections
$(BUILDDIR)/test_page_json: test_page_json.c $(TABLE_ENV) hw_mock.h | $(BUILDDIR)
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
+1 -1
View File
@@ -112,7 +112,7 @@ void read_reg_timer(uint32_t *tmr) { *tmr = 0; }
/* uip-conf.h asks uIP not to define the packet buffer: on the switch it lives
* at a fixed XDATA address, so the bench provides the storage itself. */
u8_t uip_buf[UIP_BUFSIZE + 2];
u8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE];
uint16_t strlen_x(const char *s) { return (uint16_t)strlen(s); }
+1 -1
View File
@@ -11,7 +11,7 @@
/* ---------- platform mocks ---------- */
uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
uint8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE];
uint16_t uip_len;
struct uip_eth_addr uip_ethaddr = { .addr = {0x02,0x11,0x22,0x33,0x44,0x55} };
const struct machine machine = { .min_port = 0, .max_port = 7,
+277
View File
@@ -0,0 +1,277 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "rtl837x_common.h"
#include "rtl837x_regs.h"
#include "rtl837x_nic.h"
uint8_t rx_headers[16];
/* Model the DMA behavior reported on SWTGW218AS: a transfer starting inside
* the RX ring wraps at its end. An initial address outside the ring instead
* reads flat ASIC memory, including stale TX bytes at 0x2800. */
static uint8_t asic[0x8000];
static struct {
uint8_t before[16];
uint8_t data[UIP_CONF_BUFFER_ALLOC_SIZE];
uint8_t after[16];
} destination;
struct dma_request {
uint8_t *buffer;
uint16_t ring;
uint8_t words;
};
static struct dma_request requests[8];
static unsigned request_count, fail_request;
static int failures;
static void check(bool condition, const char *what)
{
if (!condition) {
printf(" FAIL: %s\n", what);
failures++;
}
}
bool nic_rx_dma(uint8_t *buffer, uint16_t ring, uint8_t words)
{
size_t bytes = (size_t)words * 8;
unsigned call = ++request_count;
if (call <= sizeof(requests) / sizeof(requests[0]))
requests[call - 1] = (struct dma_request){ buffer, ring, words };
if (call == fail_request || !words || (size_t)ring + bytes > sizeof(asic))
return false;
if (ring < RTL837X_NIC_RX_RING_BYTES) {
for (size_t i = 0; i < bytes; i++)
buffer[i] = asic[((size_t)ring + i) % RTL837X_NIC_RX_RING_BYTES];
} else {
memcpy(buffer, asic + ring, bytes);
}
return true;
}
static void fixture_reset(void)
{
memset(asic, 0xd7, sizeof(asic));
memset(&destination, 0xa5, sizeof(destination));
memset(rx_headers, 0x6c, sizeof(rx_headers));
memset(requests, 0, sizeof(requests));
request_count = 0;
fail_request = 0;
}
static bool filled(const uint8_t *data, size_t len, uint8_t value)
{
while (len--)
if (*data++ != value)
return false;
return true;
}
static bool guards_intact(void)
{
return filled(destination.before, sizeof(destination.before), 0xa5)
&& filled(destination.after, sizeof(destination.after), 0xa5);
}
static bool requests_start_in_rx_ring(void)
{
for (unsigned i = 0; i < request_count; i++) {
if (i >= sizeof(requests) / sizeof(requests[0]) || !requests[i].words
|| (requests[i].ring & 7)
|| requests[i].ring >= RTL837X_NIC_RX_RING_BYTES)
return false;
}
return true;
}
static void ring_write(uint16_t offset, const uint8_t *data, size_t len)
{
for (size_t i = 0; i < len; i++)
asic[((size_t)offset + i) % RTL837X_NIC_RX_RING_BYTES] = data[i];
}
static void put_descriptor(uint16_t offset, uint16_t len)
{
uint8_t descriptor[8] = { 0x03, 0x00, 0xb0, 0xc8, len, len >> 8, 0, 0 };
ring_write(offset, descriptor, sizeof(descriptor));
}
static void expect_descriptor(uint16_t len)
{
uint8_t descriptor[8] = { 0x03, 0x00, 0xb0, 0xc8, len, len >> 8, 0, 0 };
check(!memcmp(rx_headers, descriptor, sizeof(descriptor)), "the first eight descriptor bytes stay intact");
}
static void pattern(uint8_t *data, size_t len)
{
for (size_t i = 0; i < len; i++)
data[i] = (uint8_t)(i * 37 + (i >> 8) + 0x13);
}
static void t_last_descriptor(void)
{
static const uint8_t root_bpdu[68] = {
0x01, 0x80, 0xc2, 0, 0, 0, 0xd0, 0xea, 0x11, 0x12, 0x34, 0x56,
0x88, 0x99, 0x04, 0, 0, 0, 0, 8,
0, 0x27, 0x42, 0x42, 3, 0, 0, 2, 2, 0x3c,
0x10, 0, 0xd0, 0xea, 0x11, 0x12, 0x34, 0x56, 0, 0, 0, 0,
0x10, 0, 0xd0, 0xea, 0x11, 0x12, 0x34, 0x56, 0x80, 0x0a,
0, 0, 0x14, 0, 2, 0, 0x0f, 0, 0
};
uint8_t stale_tx[72] = { 0 };
uint16_t last = RTL837X_NIC_RX_RING_BYTES - 8;
printf("[test] the last RX descriptor wraps its BPDU payload before DMA\n");
fixture_reset();
put_descriptor(last, sizeof(root_bpdu));
ring_write(0, root_bpdu, sizeof(root_bpdu));
memcpy(stale_tx, root_bpdu, sizeof(root_bpdu));
stale_tx[17] = 0x20;
stale_tx[19] = 1; /* retained TX destination mask, not ingress port 8 */
memcpy(asic + RTL837X_NIC_RX_RING_BYTES, stale_tx, sizeof(stale_tx));
check(nic_rx_header(last), "the final descriptor is readable");
expect_descriptor(sizeof(root_bpdu));
check(nic_rx_packet(destination.data, last + 8), "a payload address at the RX ring limit wraps to zero");
check(!memcmp(destination.data, root_bpdu, sizeof(root_bpdu)), "the complete upstream BPDU is read instead of stale TX bytes");
check(destination.data[19] == 8, "the upstream ingress tag survives the ring boundary");
check(request_count == 2 && requests[0].ring == last && requests[0].words == 1
&& requests[1].ring == 0 && requests[1].words == 9,
"descriptor and rounded payload DMA both start in the RX ring");
check(requests_start_in_rx_ring() && guards_intact(), "DMA starts inside the RX ring and preserves destination guards");
expect_descriptor(sizeof(root_bpdu));
}
static void t_payload_layouts(void)
{
static const struct {
uint16_t descriptor, len;
} cases[] = {
{ 0x0100, 8 }, { 0x0100, 16 }, { 0x0100, 64 },
{ 0x0100, 68 }, { 0x0100, 72 },
{ RTL837X_NIC_RX_RING_BYTES - 16, 8 },
{ RTL837X_NIC_RX_RING_BYTES - 16, 16 },
{ RTL837X_NIC_RX_RING_BYTES - 16, 68 },
{ RTL837X_NIC_RX_RING_BYTES - 72, 64 },
{ RTL837X_NIC_RX_RING_BYTES - 48, 68 }
};
uint8_t frame[80];
printf("[test] payload DMA handles ordinary, exact-boundary, and crossing frames\n");
pattern(frame, sizeof(frame));
for (unsigned i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
size_t rounded = (cases[i].len + 7u) & ~7u;
fixture_reset();
put_descriptor(cases[i].descriptor, cases[i].len);
ring_write(cases[i].descriptor + 8, frame, rounded);
check(nic_rx_header(cases[i].descriptor), "the descriptor transfer completes");
check(nic_rx_packet(destination.data, cases[i].descriptor + 8), "the payload transfer completes");
check(!memcmp(destination.data, frame, rounded), "every payload and permitted padding byte reaches the correct destination offset");
check(filled(destination.data + rounded, sizeof(destination.data) - rounded, 0xa5), "DMA does not write beyond the rounded frame");
check(request_count == 2, "the payload uses one DMA request even when crossing the ring end");
check(requests_start_in_rx_ring() && guards_intact(), "crossing DMA starts inside the RX ring and preserves destination guards");
expect_descriptor(cases[i].len);
}
}
static void t_maximum_frames(void)
{
uint8_t frame[(UIP_CONF_BUFFER_SIZE + 7u) & ~7u];
static const uint16_t lengths[] = { 1, 7, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556 };
printf("[test] rounded maximum frames fit without overwriting their descriptor\n");
pattern(frame, sizeof(frame));
for (unsigned layout = 0; layout < 3; layout++) {
uint16_t descriptor = layout == 0 ? 0x0100
: RTL837X_NIC_RX_RING_BYTES - (layout == 1 ? 16 : 8);
for (unsigned i = 0; i < sizeof(lengths) / sizeof(lengths[0]); i++) {
uint16_t len = lengths[i];
size_t rounded = (len + 7u) & ~7u;
fixture_reset();
put_descriptor(descriptor, len);
ring_write(descriptor + 8, frame, rounded);
check(nic_rx_header(descriptor), "the maximum-frame descriptor transfer completes");
check(nic_rx_packet(destination.data, descriptor + 8), "all supported frame lengths fit the destination");
check(!memcmp(destination.data, frame, rounded), "the full rounded frame is preserved");
check(filled(destination.data + rounded, sizeof(destination.data) - rounded, 0xa5), "rounded DMA writes no bytes beyond the available destination");
check(request_count == 2, "maximum frames use a single payload DMA request");
check(requests_start_in_rx_ring() && guards_intact(), "rounded DMA starts inside the RX ring and preserves destination guards");
expect_descriptor(len);
}
}
}
static void t_invalid_frames(void)
{
static const uint16_t invalid_lengths[] = { 0, UIP_CONF_BUFFER_SIZE + 1, 0xffff };
static const uint16_t invalid_pointers[] = { 1, 7, RTL837X_NIC_RX_RING_BYTES + 8, 0xfff8 };
printf("[test] invalid lengths and DMA addresses are rejected before transfer\n");
for (unsigned i = 0; i < sizeof(invalid_lengths) / sizeof(invalid_lengths[0]); i++) {
fixture_reset();
rx_headers[4] = invalid_lengths[i];
rx_headers[5] = invalid_lengths[i] >> 8;
check(!nic_rx_packet(destination.data, 0x0100), "unsupported or overflowing lengths are rejected");
check(!request_count && filled(destination.data, sizeof(destination.data), 0xa5) && guards_intact(),
"invalid frame lengths cause no DMA or destination changes");
}
for (unsigned i = 0; i < sizeof(invalid_pointers) / sizeof(invalid_pointers[0]); i++) {
fixture_reset();
rx_headers[4] = 68;
rx_headers[5] = 0;
check(!nic_rx_header(invalid_pointers[i]), "an invalid descriptor address is rejected");
check(!nic_rx_packet(destination.data, invalid_pointers[i]), "an invalid payload address is rejected");
check(!request_count && guards_intact(), "invalid addresses never reach DMA");
}
fixture_reset();
check(!nic_rx_header(RTL837X_NIC_RX_RING_BYTES) && !request_count,
"a descriptor at the ring limit is rejected rather than wrapped");
}
static void t_dma_failure(void)
{
uint8_t frame[UIP_CONF_BUFFER_ALLOC_SIZE];
static const uint16_t lengths[] = { 68, UIP_CONF_BUFFER_SIZE };
printf("[test] failed descriptor and single-payload DMA transfers propagate failure\n");
fixture_reset();
fail_request = 1;
check(!nic_rx_header(0x0100) && request_count == 1, "descriptor DMA failure reaches the caller");
pattern(frame, sizeof(frame));
for (unsigned layout = 0; layout < 3; layout++) {
uint16_t descriptor = layout == 0 ? 0x0100
: RTL837X_NIC_RX_RING_BYTES - (layout == 1 ? 16 : 8);
for (unsigned i = 0; i < sizeof(lengths) / sizeof(lengths[0]); i++) {
uint16_t len = lengths[i];
fixture_reset();
put_descriptor(descriptor, len);
ring_write(descriptor + 8, frame, (len + 7u) & ~7u);
check(nic_rx_header(descriptor), "the descriptor precedes the injected payload failure");
fail_request = 2;
check(!nic_rx_packet(destination.data, descriptor + 8), "payload DMA failure reaches the caller");
check(request_count == fail_request, "a failed payload DMA is not retried or split");
check(filled(destination.data, sizeof(destination.data), 0xa5) && guards_intact(),
"an injected failure before DMA preserves the destination and guards");
expect_descriptor(len);
}
}
}
int main(void)
{
t_last_descriptor();
t_payload_layouts();
t_maximum_frames();
t_invalid_frames();
t_dma_failure();
if (failures) {
printf("%d NIC RX check(s) failed\n", failures);
return 1;
}
puts("all NIC RX checks passed");
return 0;
}
+4
View File
@@ -132,6 +132,10 @@ typedef unsigned short uip_stats_t;
*/
#define UIP_CONF_BUFFER_SIZE 1556
/* Backing storage includes padding for the NIC's eight-byte DMA transfers.
* Keep UIP_CONF_BUFFER_SIZE as the logical frame/MSS limit. */
#define UIP_CONF_BUFFER_ALLOC_SIZE ((UIP_CONF_BUFFER_SIZE + 7U) & ~7U)
/**
* Bytes of the buffer kept out of the advertised MSS.
*
+1 -1
View File
@@ -136,7 +136,7 @@ static __code const uip_ipaddr_t all_zeroes_addr =
#endif /* UIP_CONF_IPV6 */
#ifndef UIP_CONF_EXTERNAL_BUFFER
u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains
u8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE]; /* The packet buffer that contains
incoming packets. */
#endif /* UIP_CONF_EXTERNAL_BUFFER */
+1 -1
View File
@@ -419,7 +419,7 @@
#endif /* UIP_CONF_BUFFER_EXTRA */
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE];
/**
* Determines if statistics support should be compiled in.