Support for RTL838x based managed switches

DGS-1210-28 has non-working SFP-s because the SFP buses are not described and attached in the DTS at all.

1 Like

Hi, let me be a bit more specific. The GS 1900-10HP has the I2C busses for EEPROMS on the SFP modules desribed in the .dts. This enables features like hot plugging, reading out the EEPROMS, handling of Loss of signal and disabling the LEDs when not active. The kernel also knows what type of module is used such as SX, LX and the like and can adjust accordingly. This is not strictly necessary, to make SFP work. Some devices don't have the I2C bus described, either because of the gpiolib limitations or because the GPIOs are not known. Many things still work. I am just now developing on a Netgear GS728TPv2 and while I can have support for I2C on 2 out of the 4 ports (the other 2 share the clock lines with the first 2 ports), I have 1GBit copper and 1GBit SX modules happily working in any of these slots, however no hotplugging and no link adjustments other than what autoconf provides. So the SFP slots work with some basic functionality even without I2C bus support.

If you want to get the I2C busses working, then it is easiest if the OEM firmware supports the "show tech-support" command which will show the complete GPIO configuration of the SFP ports. Just add this to the .dts and that's it. If this command is not available, one needs a modified SFP module which allows to measure continuity between its interface pins and the pins of typically the RTL8231 GPIO expander it connects to.

That's all understood, the GPIO pins and I2C pins are known for 2 of the 4 SFP ports and with them, it will work fine.
For me, I count SFP ports not working properly if there is no way to automatically toggle the PHY mode based on the plugged SFP and for that you always need the SFP bus described with GPIO-s as well so that PHYLINK can be used

The other 2 need to be traced manually as there is no "show tech-support" or similar in D-Link FW

1 Like

I think the ethtool command will always returns "Twisted Pair" on combo port regardless of whether it has been switched to Fibre. The current phy driver won't update the port information when switching.

1 Like

Hi, I went through all the conversation one month ago but I didn't had the time to join in

I have a spare Zyxel XGS1010-12 (hardware is same as XGS1210-12) and also various usb-uart converters, but is not clear to me the proper procedure to flash this device

Any help is very appreciated, hoping ti give back to the community

Thanks,
Luca

I have submitted a PR supporting the ZyXEL GS1900-24HPv1, 24-plus-2-port managed PoE switch.

4 Likes

There is no support for this device at the moment in master, i.e. there are no images available. If you know how to compile an image yourself, you can use the current master, use one of the .dts that was mentioned earlier for the Zyxel XGS1210-10 and install that.

When you have set up multi VLAN switches on these Realtek devices.
Have you actually used firewall zone security in the switch or do you use the “dumb access point” way of doing it with unmanaged interfaces or simply only use L2 switching without any interface at all for each “data” VLAN.
And for management make a VLAN with a DHCP client or similar interface.

And have all interface and firewall handling made in the router (as usual).

1 Like

I started trying to add 5.15 support for realtek target.

https://wiki.taiha.net/en/openwrt/devel/realtek-target_5_15

Currently, this can be compiled and booted, but network is broken. I investegated about it, but I haven't found the cause yet...

7 Likes

I managed to get USB support going on the Netgear GS728TPv2:

root@OpenWrt:/# cat /proc/cpuinfo 
system type             : RTL8391
machine                 : Netgear GS728TPv2
processor               : 0
cpu model               : MIPS 34Kc V5.5
BogoMIPS                : 464.48
wait instruction        : yes
microsecond timers      : yes
tlb_entries             : 32
extra interrupt vector  : yes
hardware watchpoint     : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
isa                     : mips1 mips2 mips32r1 mips32r2
ASEs implemented        : mips16 dsp mt
Options implemented     : tlb 4kex 4k_cache 32fpr prefetch mcheck ejtag llsc pindexed_dcache userlocal vint perf_cntr_intr_bit perf
shadow register sets    : 1
kscratch registers      : 0
package                 : 0
core                    : 0
VPE                     : 0
VCED exceptions         : not available
VCEI exceptions         : not available

processor               : 1
cpu model               : MIPS 34Kc V5.5
BogoMIPS                : 466.94
wait instruction        : yes
microsecond timers      : yes
tlb_entries             : 32
extra interrupt vector  : yes
hardware watchpoint     : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
isa                     : mips1 mips2 mips32r1 mips32r2
ASEs implemented        : mips16 dsp mt
Options implemented     : tlb 4kex 4k_cache 32fpr prefetch mcheck ejtag llsc pindexed_dcache userlocal vint perf_cntr_intr_bit perf
shadow register sets    : 1
kscratch registers      : 0
package                 : 0
core                    : 0
VPE                     : 1
VCED exceptions         : not available
VCEI exceptions         : not available
root@OpenWrt:/# [   89.462624] usb 1-1: new full-speed USB device number 3 using max3421-hcd
[   89.760532] usb-storage 1-1:1.0: USB Mass Storage device detected
[   89.776501] scsi host0: usb-storage 1-1:1.0
[   90.878904] scsi 0:0:0:0: Direct-Access     Generic  Flash Disk       1.68 PQ: 0 ANSI: 2
[   90.894944] sd 0:0:0:0: Attached scsi generic sg0 type 0
[   90.985936] sd 0:0:0:0: [sda] 7884800 512-byte logical blocks: (4.04 GB/3.76 GiB)
[   91.026708] sd 0:0:0:0: [sda] Write Protect is off
[   91.032169] sd 0:0:0:0: [sda] Mode Sense: 03 00 00 00
[   91.053912] sd 0:0:0:0: [sda] No Caching mode page found
[   91.059947] sd 0:0:0:0: [sda] Assuming drive cache: write through
[   91.220375]  sda: sda1
[   91.321304] sd 0:0:0:0: [sda] Attached SCSI removable disk

root@OpenWrt:/# lsusb
Bus 001 Device 003: ID 1908:1320 Generic Mass storage
Bus 001 Device 001: ID 1d6b:0002 Linux 5.10.100 max3421 MAX3421 USB Host-Controller Driver

It works via a slow MAX3421E spi-usb-bridge. Quite a few changes for the SPI driver were necessary to support Chip Select and the semi-full-duplex the max3421 uses. Also the max3421-hcd driver needed some changes, since the RTL8390 does not support level-low IRQs on its GPIOs.
I also have the SFP ports working and wrote a LED driver for the 8390 (this was not necessary on the GS1900-48 because u-boot already initializes the LEDs). There are still some fans which are controlled via an MSP430 muC and probably a thermal sensor. The device has 190W of PoE, so I want the fans to work before testing that.

BTW: Does anyone know what I am missing here:

root@OpenWrt:/# mkdir /tmp/mnt
root@OpenWrt:/# ls -l /dev/sda1 
brw-------    1 root     root        8,   1 Mar 26 19:04 /dev/sda1
root@OpenWrt:/# mount -t vfat /dev/sda1 /tmp/mnt
mount: mounting /dev/sda1 on /tmp/mnt failed: No such device
3 Likes

I just looked at it. Great work!
I see that ping packets are leaving the switch, but then they are dropped when the reply is being received. I tested on the 839x device I am just working on and I see drops that are very strange:

root@OpenWrt:/# ping 192.168.2.150
PING 192.168.2.150 (192.168.2.150): 56 data bytes
^C
--- 192.168.2.150 ping statistics ---
21 packets transmitted, 0 packets received, 100% packet loss
root@OpenWrt:/# cat /sys/kernel/debug/rtl838x/drop_counters 
ALE_TX_GOOD_PKTS: 24   <<<<<<<<<<<<<< transmitted pings with ARP lookup
ERROR_PKTS: 0
EGR_ACL_DROP: 0
EGR_METER_DROP: 0
OAM: 0
CFMVLAN_IGR_FLTR: 0
VLAN_ERR: 0
INNER_OUTER_CFI_EQUAL_1: 0
VLAN_TAG_FORMAT: 0
SRC_PORT_SPENDING_TREE: 0
INBW: 0
RMA: 0
HW_ATTACK_PREVENTION: 0
PROTO_STORM: 0
MCAST_SA: 0
IGR_ACL_DROP: 0
IGR_METER_DROP: 0
DFLT_ACTION_FOR_MISS_ACL_AND_C2SC: 0
NEW_SA: 0
PORT_MOVE: 0
SA_BLOCKING: 0
ROUTING_EXCEPTION: 0
SRC_PORT_SPENDING_TREE_NON_FWDING: 0
MAC_LIMIT: 0
UNKNOW_STORM: 19                                     <<<<<<<<<<<<<<<<<<<<<<<<<
MISS_DROP: 0
CPU_MAC_DROP: 0
DA_BLOCKING: 0
SRC_PORT_FILTER_BEFORE_EGR_ACL: 0
VLAN_EGR_FILTER: 0
SPANNING_TRE: 0
PORT_ISOLATION: 0
OAM_EGRESS_DROP: 0
MIRROR_ISOLATION: 0
MAX_LEN_BEFORE_EGR_ACL: 0
SRC_PORT_FILTER_BEFORE_MIRROR: 0
MAX_LEN_BEFORE_MIRROR: 0
SPECIAL_CONGEST_BEFORE_MIRROR: 0
LINK_STATUS_BEFORE_MIRROR: 0
WRED_BEFORE_MIRROR: 0
MAX_LEN_AFTER_MIRROR: 0
SPECIAL_CONGEST_AFTER_MIRROR: 0
LINK_STATUS_AFTER_MIRROR: 0
WRED_AFTER_MIRROR: 0
ALE_TX_GOOD_PKTS: 0

I repeated this a couple of times and the number of pings returned seems to match more or less the number of UNKNOWN_STORM drops (every time you read the drop counter it gets reset by the HW).
The packet storm handling should however be completely independent on the kernel version, there is just some hopefully sane default configured. My suspicion is the bridge code, which was changed between 5.10 and 5.15, in particular the L2 learning handling. Maybe the HW believes there is a packet storm because it receives packets with its own MAC address, e.g. because of strange flooding or disabled learning. I will look further...

2 Likes

There seems to be a stack of 7 of these models on eBay right now if people are looking for additional victims^h^h^h devices to test - strangely it looks like that stack of 7 is about the price of what one usually goes for so I'm not 100% it is legit but they are used.

Since there is an eJTAG header on the Zyxel GS1900-48, I configured those pins for GPIO use, and added a fake gpio-key on the TDI pin (gpio0-6):

/ {
	compatible = "zyxel,gs1900-48", "realtek,rtl8393-soc";
	model = "ZyXEL GS1900-48";

	keys {
		compatible = "gpio-keys";

		pinctrl-names = "default";
		pinctrl-0 = <&jtag_pins>;

		fake_reset {
			gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
			linux,code = <KEY_RESTART>;
		};
	};

	soc@18000000 {
		compatible = "simple-bus";
		#address-cells = <1>;
		#size-cells = <1>;
		ranges = <0x0 0x18000000 0x10000>;

		gpio0: gpio@3500 {
			compatible = "realtek,rtl8380-gpio", "realtek,otto-gpio";
			reg = <0x3500 0x1c>;

			gpio-controller;
			#gpio-cells = <2>;
			ngpios = <24>;

			interrupt-controller;
			#interrupt-cells = <2>;
			interrupt-parent = <&intc>;
			interrupts = <23 2>;
		};
	};

	switchcore-bus@1b000000 {
		compatible = "simple-bus";
		#address-cells = <1>;
		#size-cells = <1>;
		ranges = <0x0 0x1b000000 0x20000>;

		pinctrl_jtag: pinmux@4 {
			compatible = "pinctrl-single";
			reg = <0x0004 0x4>;

			pinctrl-single,bit-per-mux;
			pinctrl-single,register-width = <32>;
			pinctrl-single,function-mask = <0x1>;
			#pinctrl-cells = <2>;

			jtag_pins: pinmux_jtag_pins {
				pinctrl-single,bits = <0x0 0x0002 0x0003>;
			};
		};
	};
};

I then get the following log output when I pull TDI to ground (it has a pull-up on the board):

[   51.899181] evbug: Event. Dev: input0, Type: 1, Code: 408, Value: 1
[   51.906197] evbug: Event. Dev: input0, Type: 0, Code: 0, Value: 0
[   52.083182] evbug: Event. Dev: input0, Type: 1, Code: 408, Value: 0
[   52.090197] evbug: Event. Dev: input0, Type: 0, Code: 0, Value: 0

So interrupts definitely work on my RTL8393M. How are you configuring the GPIO controller?

I did mean logic-level low IRQs. Not GPIO IRQs in general. The IMR of the internal GPIOs only has 2 bits per GPIO: 0: disabled, 1: rising edge, 2: falling edge, 3 both edges. The external GPIO interrupts on the RTL93xx have the same problem.
So this does not work (the IRQ flowtype is wrong):

	max3421@0 {
		compatible = "maxim,max3421";
		reg = <1>;
		maxim,vbus-en-pin = <8 1>;
		spi-max-frequency = <26000000>;
		interrupt-parent = <&gpio0>;
		interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
		interrupt-names = "usb";

		gpio-reset = <&gpio1 25 GPIO_ACTIVE_LOW>;
	};

But this works:

	max3421@0 {
		compatible = "maxim,max3421";
		reg = <1>;
		maxim,vbus-en-pin = <8 1>;
		spi-max-frequency = <26000000>;
		interrupt-parent = <&gpio0>;
		interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
		interrupt-names = "usb";

		gpio-reset = <&gpio1 25 GPIO_ACTIVE_LOW>;
	};

I assume the GPIO triggers on the falling edge to hit GPIO_ACTIVE_LOW.
The isssue is that the MAX3421 driver is written to work with logic level low IRQs. But the chip actually supports also falling edge IRQs, so one just has to change the driver logic and the MAX3421 configuration.

I have put all the MAX3421 stuff, the improved SPI driver, the Ubiquity USW, Zyxel XGS1210, Netgear GS728TPv2 support, the RTL8390 LEDs driver and some PHY stuff into this branch:
https://github.com/bkobl/openwrt/tree/rtl8214qf
It still needs lots of testing. I am not even sure the SPI driver works on the RTL93xx and I might have forgotten some stuff that I am playing around with, did not commit yet but is actually necessary.
Concerning the fans on the GS728TPv2: they actually seem to work out of the box. There is an additional I2C bus with an ominous device 0x48 on it which controls the muC that controls the fans. But the MSP430 seems to do the right thing automatically making use of the internal thermal sensor of the MSP430. Probably however it is easy to figure out how the fans can be directly steered: simply probing the device with i2cdump turns the fans into turbines. So probably the protocol is very simple.

Ah, interrupt type, not interrupts in general! I must've read low-level instead of level-low :confused:

Falling edge should be mostly similar, although you can indeed miss an initially asserted IRQ in that case.

1 Like

That MAX3421 patch is a rather dirty hack that will never get accepted upstream. I think you'll need to submit two patches:

  1. You want to list a GPIO as a reset, so the property must be named reset-gpios, not gpio-reset. Then you should use devm_gpiod_get() or devm_gpiod_get_optional() to get a reference to this GPIO. At first sight, the reset pin does not appear implemented currently, so the _optional interface would be the way to go. Then you also shouldn't error out if the reset cannot be found, since the MAX3421 driver already appears to implement a register based reset.
  2. I think you should be able to use irq_get_trigger_type() to read the requested interrupt type. If that works, you can use this information to conditionally configure the chip's interrupt output, instead of hard coding the behaviour.
2 Likes

I did not think this would be ever able to make it upstream, but with your suggestions it might be possible. There is still the issue of the worker thread. The

schedule_timeout(1); // Needed for falling-edge trigger

is also a very dirty hack. This comes straight from the max3421 driver in the SDK and I would need to learn a lot more about the topic to properly handle this. Plus one needs to have different behaviors for the thread in case of the use of level-low IRQs.

When getting this to work I spent tons of time on getting the SPI to work. It starts out with the interesting finding that the MAX3421 only supports up to 26MHz clocks, whereas the RTL83xx and the primary (but not secondary) SPI controller on the RTL93xx only support exactly 50MHz according to the datasheets. So I had to get a logic analyzer that could reliably sample at at least 100MHz to look into what was going on. That stuff is either not available at the moment or has to be weighed up in gold, plus once you got one you still have to fight HF noise on the bus. It turns out the default settings of the SPI bus on the RTL SoCs use 25MHz, but the divider is fixed at a relatively high value of 7, so maybe more would be possible. Which brings us to the fact that the MAX3421 driver is itself quite dirty. It needs a full-duplex SPI, but then only uses half-duplex features, have a look at spi_rd8(). It sends 2 bytes (second only pro-forma 0) but reads only the second byte received, which is half-duplex. I tried for days to make the SPI controller on the RTL839x do full-duplex and I am not convinced it is not possible, but at some point I gave up. Maybe that is the reason the RTL93xx have a second completely different SPI controller in addition, which is used on the RTL93xx devices to talk to the MAX3421 (see in the SDK system/drv/spi/spi_dev4.c, grep for MAX3421. This is actually another partial re-implementation of the MAX3421 driver.) instead. So there would likely need to be yet another different behavior of the MAX3421 driver to support that. Anyway, also the SPI driver is a hack to support that strange semi-full-but-not-really-half-duplex behavior of the MAX3421 in the kernel, see transfer_one_message() which has a special case for the MAX3421 drivers strange needs. The MAX3421 driver in the kernel is all the more strange because the full-duplex feature is not used (it would allow to get a status byte for free on any transfer) and the MAX3421 also supports half-duplex. So maybe better patch the MAX3421 driver to optionally support half-duplex and only support half duplex in the spi-driver?

This bug:

[ 2184.754425] do_page_fault(): sending SIGSEGV to realtek-poe for invalid write access to 004020cc
[ 2184.764434] epc = 77dbeff9 in libubox.so.20211120[77dba000+17000]
[ 2184.771449] ra  = 00401487 in realtek-poe[400000+3000]

... ended up being because when port 9 is initialized, libubox calls back poe_stream_msg_cb to dump data into struct port_config ports[MAX_PORTS]; this fails because #define MAX_PORT 8.

1 Like

Nice catch!

My GS1900-8HP has just 8 ports, so I guess my issue is different - how would I go about debugging this? Because right now what realtek-poe -d is spitting out doesn't seem to help much.