ixgbe, mdio, and marvell ethernet switches

From: Adrian Chadd <adrian_at_freebsd.org>
Date: Mon, 28 Apr 2025 04:00:17 UTC
A few weeks ago I started poking at some netgate hardware to use as freebsd
wifi test boxes in my little test lab here. The two I'm using are ADI (now
Silicom) boxes that needed some fun deep dives into BIOS versions,
interrupt storms and compatible mini-PCIe cards (some just don't actually
get probed!)

Anyway.

I ended up stumbling across one of the Silicom OEM boxes that got turned
into an AT&T open compute platform box back in 2018/2019 that has an
integrated Marvell 88E6190X switch hanging off of the intel X553 backplane
(the ixgbe driver.) However, it wasn't supported in FreeBSD, and the
instructions to get the switch up in linux were hit and miss.

People had gotten the etherswitch driver patched to work, but only against
pfsense plus, which has the MDIO support for ixgbe. But, I couldn't find
any diffs online to implement it.

So I did what I normally do, I got distracted from wifi stuff and decided
to get it going. Having a working amd64 etherswitch platform would be nice
for general etherswitch tinkering outside of the arm/mips/ppc world, and
then no-one would have any excuses getting involved in improving it!

It took a few days, but I figured it out. Here's the fun deep dive.

Firstly, DPDK introduced some support for the MDIO bus being exposed on the
X553, but with a couple caveats:

* it started as clause 22 (which is PHYs pre-2000) diff , but it eventually
got turned into a clause 45 (PHYs post-2000) diff, and they .. just deleted
the clause 22 code
* the MDIO support is really focused on talking MDIO to the PHYs internally
inside the X550 series hardware - clause 45, fixed PHY number, etc

So it wasn't enough to really bring up the marvell switch, as these all
seem to want clause 22 MDIO commands.

Then i went digging into the X550 and X553 datasheets.

* the X550 datasheet says that it only supports clause 45
* the X553 datasheet says it supports both clause 22 and clause 45, but
makes a point of (a) telling you if you need to, you should speak into
intel customer engineering, and (b) deleted the MDIO registers from their
register programming guide

Ok, so the X553 does do Clause 22, but .. how.

Then I went through the DPDK and linux driver history and lo and behold,
linux actually HAS the correct mdio bus support! specifically, they have a
/separate/ mdio bus driver hiding in their X550/X553 support, which:

* handles both clause 22 and clause 45 IO
* does the correct semaphore handshaking, since MDIO is shared between
multiple ethernet MACs, hardware and firmware
* exposes only one MDIO bus on the X553, as it only has a single MDIO bus
shared between the 1 to 4 MACs the chipset can expose

Armed with that I committed some driver sins and got it working. The in
progress absolutely disgusting hack diff is attached, so it won't get lost
/ forgotten.

Anyway, on the etherswitch side I did a bunch of cleanup to support
etherswitch/miiproxy/e6000sw as modules, and fix a bunch of e6000sw bugs,
and they're in -HEAD:

* https://reviews.freebsd.org/D50024 to https://reviews.freebsd.org/D50031
are all cleanups
* https://reviews.freebsd.org/D50044 adds the 88E6190X support

But then the next fun problem - none of the ports came up. Well, I lie.
Only one of them came up. I went digging into the PHY registers and found
that the marvell gige PHY code didn't actually power up the PHY if it was
powered down, so I fixed that too:

* https://reviews.freebsd.org/D50045

Then with some hints, I could see and use all of the switch ports on the
AT&T ATT-150 CPE device:

hint.mdio.0.at="ix0"
hint.e6000sw.0.addr="0x10"
hint.e6000sw.0.port0disabled="1"
hint.e6000sw.0.is6190x=1
hint.e6000sw.0.port9cpu=1
hint.e6000sw.0.port10cpu=1
hint.e6000sw.0.port9speed=2500
hint.e6000sw.0.port10speed=2500

Then, I also acquired a wireguard M270 box, as it also apprently has a
marvell switch attached to an X553 backplane, and none of the ethernet
ports work at all out of the box.
The above hints worked on that too - with addr set to "0x0" instead of
"0x10".

So, now i have two Atom C3558 boxes w/ X553 2.5gbit backplane ports hooked
into an 8 port marvell gige switch working on -HEAD (save the ixgbe mdio
diff that I attached; I'll sort that out soon). All it took was like $250
in hardware, staring at intel documentation and linux/dpdk driver code, and
three evenings thinking to myself "surely this can't be THAT hard.