[BMIPS] Internal switch does not work. dsa_register_switch returns -22 Invalid Argument

Hello guys,

I'm trying to add support for Sagemcom F@st3864OP, which has a BCM63168 dual-core CPU with a built-in switch and an external switch BCM53124S.

I'm targeting the latest tag (), as its new BMIPS branch adds support for the external MDIO. The external MDIO is required to recognize BCM53124S. I have made the following changes:

$ git status
On branch 22.03.0-rc5-fast3864op
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   target/linux/bmips/image/bcm63xx_nand.mk
        modified:   target/linux/bmips/nand/base-files/etc/board.d/01_leds
        modified:   target/linux/bmips/nand/base-files/etc/board.d/02_network

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        target/linux/bmips/dts/bcm63168-sagem-fast-3864op.dts

More details and the repo can be found at:

However, the internal switch does not work at all, also the mdio command can show the port status of both the internal and the external switch. The boot log shows:

[    2.332493] b53-switch 10700000.switch: found switch QwQ: BCM63xx, rev 0
[    2.339592] b53-switch 10700000.switch: QwQ dsa_register_switch()=-22
[    2.346306] b53-switch: probe of 10700000.switch failed with error -22

I added some printk to assist debugging, starting with "QwQ". It turns out that the
dsa_register_switch in b53_common.h failed. The error code -22 suggests "Invalid Argument": #define EINVAL 22 /* Invalid argument */ .

Anyone has any idea on this? Should I insert more printk inside dsa_register_switch?

Thanks

After inserting a whole bunch of "printk", for the external switch, it shows that the call to "dsa_port_parse_of(dp, port);" returns -517 in function "dsa_switch_parse_ports_of()" of "net/dsa/dsa2.c". "-517" is EPROBE_DEFER, which indicates "Driver requests probe retry". Here is my DTS for the external switch:

&mdio_ext {
	switch@1e {
		compatible = "brcm,bcm53125";
		reg = <30>;

		ports {
			#address-cells = <1>;
			#size-cells = <0>;

			port@1 {
				reg = <1>;
				label = "lan1";
			};

			port@2 {
				reg = <2>;
				label = "lan2";
			};

			port@3 {
				reg = <3>;
				label = "lan3";
			};

			port@4 {
				reg = <4>;
				label = "lan4";
			};

			cpu@8 {
				reg = <8>;
				label = "cpu";

				ethernet = <&ethernet>;

				fixed-link {
					speed = <1000>;
					full-duplex;
					asym-pause;
					pause;
				};
			};
		};
	};
};

For the internal switch, it shows that the function "dsa_switch_parse_ports_of" cannot find a valid "num_port":

...
	for_each_available_child_of_node(ports, port) {
		err = of_property_read_u32(port, "reg", &reg);
		dev_info(ds->dev, "QwQ: dsa_switch_parse_ports_of() of_property_read_u32(port, \"reg\", &reg) = %d\n", err);
		if (err)
			goto out_put_node;
...

According to my debug "printk", "ds->num_ports" is 5, which does not seem to be correct. According to the code in the "BCM63xx" target, "ds->num_ports" should be 9: 3 x FE PHY, 1 x GE PHY, 4 x RGMII MAC-PHY interface, and 1 internal CPU port. I will try to patch it.

I confirmed that it is a bug, and has been addressed in:

But it has not been included in the recent v22.03.0-rc5, I will try the latest master branch and see if it fixes this issue along with other problems.

I tried the master branch (as of 2022 07 20), which has fixed "B53_CPU_PORT" problem. Without specifying the external switch in the dts, the image boots, the wan port works but the LAN ports don't. Then, I attempted to add the external switch to the dts, and the image doesn't boot anymore. The following is the boot log:

[    2.086792] bcm6368-mdio-mux 107000b0.mdio: Broadcom BCM6368 MDIO mux bus
[    2.095453] bcm53xx 0.1:1e: found switch: BCM53125, rev 4
[    2.101076] bcm53xx 0.1:1e: failed to register switch: -517
[    2.107601] b53-switch 10700000.switch: found switch: BCM63xx, rev 0
[    2.118387] bcm6368-enetsw 1000d800.ethernet: mtd mac d8:d7:75:13:03:72
[    2.248248] bcm7038-wdt 1000009c.watchdog: Registered BCM7038 Watchdog
[    2.261817] NET: Registered PF_INET6 protocol family
[    2.298322] Segment Routing with IPv6
[    2.302295] In-situ OAM (IOAM) with IPv6
[    2.306643] NET: Registered PF_PACKET protocol family
[    2.312635] 8021q: 802.1Q VLAN Support v1.8
[    2.349723] bcm53xx 0.1:1e: found switch: BCM53125, rev 4
[    2.355488] bcm53xx 0.1:1e: failed to register switch: -517
[    2.361827] b53-switch 10700000.switch: found switch: BCM63xx, rev 0
^ Stucked at this line

I also tried to disable the internal switch, that image boots with the external switch identified. It seems that the b53 driver cannot have two different switches... Needs more printk...

My printk method shows that line 920 (err = mdiobus_register(ds->slave_mii_bus);) of net/dsa/dsa2.c never returns, this function calls "phydev = mdiobus_scan(bus, I);", which then calls:

	case MDIOBUS_C22:
		phydev = get_phy_device(bus, addr, false);

In get_phy_device, r = get_phy_c22_id(bus, addr, &phy_id); never returns, as this function call blocks indefinitely:

	/* Grab the bits from PHYIR1, and put them in the upper half */
	phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);

This is not a dead-lock situation, as in function __mdiobus_read of mdio_bus.c, Assertion lockdep_assert_held_once passes. Function call retval = bus->read(bus, addr, regnum); does not return.

I believe there is a bug in the mdio driver, so I post an issue: