Download raw body.
sys/cnmac: read HW address from DTS when available
On Mon, Apr 27, 2026 at 11:54:21AM +0200, Kirill A. Korinsky wrote:
> tech@,
>
> I'd like to fix cnmac to read local-mac-address from the matching DTS
> Ethernet port node, selected by the port reg.
>
> When it is missing, it keeps the old fallback.
>
> Tested on Unifi ER4 (CN70xx/CN71xx) and Unifi USG (CN50xx) without any
> impact, and on Juniper SRX300 (CN70xx/CN71xx) where chandes are:
>
> before diff:
>
> octpip0 at simplebus0
> octgmx0 at octpip0 interface 0
> cnmac0 at octgmx0: port 0 SGMII, address d0:dd:49:e0:63:80
> octgmx1 at octpip0 interface 1: no active ports found
> octgmx2 at octpip0 interface 4
> cnmac1 at octgmx2: port 24 AGL, address 00:00:00:00:00:00
>
> after diff:
>
> octpip0 at simplebus0
> octgmx0 at octpip0 interface 0
> cnmac0 at octgmx0: port 0 SGMII, address d0:dd:49:e0:63:80
> octgmx1 at octpip0 interface 1: no active ports found
> octgmx2 at octpip0 interface 4
> cnmac1 at octgmx2: port 24 AGL, address d0:dd:49:e0:63:82
This diff changes MAC addresses on the EdgeRouter Pro (and probably
ER-8 too) by swapping the MACs as follows:
cnmac0 <-> cnmac4
cnmac1 <-> cnmac5
cnmac2 <-> cnmac6
cnmac3 <-> cnmac7
This presumably relates to the quirky order of port enumeration with
this EdgeRouter model. I think the Ubiquiti firmware enumerates the GMX
interfaces in swapped order so that the OS port numbering would match
with the front panel labels. OpenBSD does not perform such a swap.
However, with this diff the cnmac(4) ports should now get the same MAC
addresses that the original firmware would assign them.
OK visa@
> Index: sys/arch/octeon/dev/cn30xxgmx.c
> ===================================================================
> RCS file: /home/cvs/src/sys/arch/octeon/dev/cn30xxgmx.c,v
> diff -u -p -r1.56 cn30xxgmx.c
> --- sys/arch/octeon/dev/cn30xxgmx.c 22 Apr 2026 19:11:04 -0000 1.56
> +++ sys/arch/octeon/dev/cn30xxgmx.c 27 Apr 2026 09:31:27 -0000
> @@ -87,6 +87,7 @@ struct cn30xxgmx_port_ops {
> int cn30xxgmx_match(struct device *, void *, void *);
> void cn30xxgmx_attach(struct device *, struct device *, void *);
> int cn30xxgmx_print(void *, const char *);
> +int cn30xxgmx_get_port_node(int, int);
> void cn30xxgmx_init(struct cn30xxgmx_softc *);
> int cn30xxgmx_rx_frm_ctl_xable(struct cn30xxgmx_port_softc *,
> uint64_t, int);
> @@ -169,6 +170,22 @@ cn30xxgmx_match(struct device *parent, v
> }
>
> int
> +cn30xxgmx_get_port_node(int node, int port)
> +{
> + int child;
> +
> + if (node == 0)
> + return 0;
> +
> + for (child = OF_child(node); child != 0; child = OF_peer(child)) {
> + if (OF_getpropint(child, "reg", (uint32_t)-1) == port)
> + return child;
> + }
> +
> + return 0;
> +}
> +
> +int
> cn30xxgmx_get_phy_phandle(int interface, int port, int *port_1000x,
> int *disable_an)
> {
> @@ -235,6 +252,7 @@ cn30xxgmx_attach(struct device *parent,
> struct cn30xxgmx_softc *sc = (void *)self;
> struct cn30xxsmi_softc *smi;
> int i;
> + int node;
> int phandle;
> int phy_addr;
> int port;
> @@ -268,6 +286,7 @@ cn30xxgmx_attach(struct device *parent,
>
> for (i = 0; i < sc->sc_nports; i++) {
> port_sc = &sc->sc_ports[i];
> + node = cn30xxgmx_get_port_node(aa->aa_node, i);
> if (sc->sc_port_types[i] == GMX_AGL_PORT)
> port = 24;
> else
> @@ -330,6 +349,7 @@ cn30xxgmx_attach(struct device *parent,
> gmx_aa.ga_name = "cnmac";
> gmx_aa.ga_portno = port_sc->sc_port_no;
> gmx_aa.ga_port_type = sc->sc_port_types[i];
> + gmx_aa.ga_node = node;
> gmx_aa.ga_gmx = sc;
> gmx_aa.ga_gmx_port = port_sc;
> gmx_aa.ga_phy_addr = phy_addr;
> Index: sys/arch/octeon/dev/cn30xxgmxvar.h
> ===================================================================
> RCS file: /home/cvs/src/sys/arch/octeon/dev/cn30xxgmxvar.h,v
> diff -u -p -r1.15 cn30xxgmxvar.h
> --- sys/arch/octeon/dev/cn30xxgmxvar.h 22 Apr 2026 19:11:04 -0000 1.15
> +++ sys/arch/octeon/dev/cn30xxgmxvar.h 27 Apr 2026 09:31:27 -0000
> @@ -95,6 +95,7 @@ struct cn30xxgmx_attach_args {
> const char *ga_name;
> int ga_portno;
> int ga_port_type;
> + int ga_node;
> struct cn30xxsmi_softc *ga_smi;
> int ga_phy_addr;
>
> Index: sys/arch/octeon/dev/if_cnmac.c
> ===================================================================
> RCS file: /home/cvs/src/sys/arch/octeon/dev/if_cnmac.c,v
> diff -u -p -r1.88 if_cnmac.c
> --- sys/arch/octeon/dev/if_cnmac.c 22 Apr 2026 19:11:04 -0000 1.88
> +++ sys/arch/octeon/dev/if_cnmac.c 27 Apr 2026 09:31:27 -0000
> @@ -51,6 +51,8 @@
> #include <sys/endian.h>
> #include <sys/atomic.h>
>
> +#include <dev/ofw/openfirm.h>
> +
> #include <net/if.h>
> #include <net/if_media.h>
> #include <netinet/in.h>
> @@ -120,6 +122,7 @@ void cnmac_ipd_init(struct cnmac_softc *
> void cnmac_pko_init(struct cnmac_softc *);
>
> void cnmac_board_mac_addr(uint8_t *);
> +int cnmac_port_mac_addr(int, uint8_t *);
>
> int cnmac_mii_readreg(struct device *, int, int);
> void cnmac_mii_writereg(struct device *, int, int, int);
> @@ -277,7 +280,8 @@ cnmac_attach(struct device *parent, stru
> */
> sc->sc_ip_offset = 0/* XXX */;
>
> - cnmac_board_mac_addr(sc->sc_arpcom.ac_enaddr);
> + if (cnmac_port_mac_addr(ga->ga_node, sc->sc_arpcom.ac_enaddr) != 0)
> + cnmac_board_mac_addr(sc->sc_arpcom.ac_enaddr);
> printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
>
> ml_init(&sc->sc_sendq);
> @@ -386,6 +390,17 @@ cnmac_pko_init(struct cnmac_softc *sc)
> }
>
> /* ---- XXX */
> +
> +int
> +cnmac_port_mac_addr(int node, uint8_t *enaddr)
> +{
> + if (node == 0)
> + return 1;
> + if (OF_getprop(node, "local-mac-address", enaddr, ETHER_ADDR_LEN) ==
> + ETHER_ADDR_LEN)
> + return 0;
> + return 1;
> +}
>
> void
> cnmac_board_mac_addr(uint8_t *enaddr)
> Index: sys/arch/octeon/dev/iobusvar.h
> ===================================================================
> RCS file: /home/cvs/src/sys/arch/octeon/dev/iobusvar.h,v
> diff -u -p -r1.5 iobusvar.h
> --- sys/arch/octeon/dev/iobusvar.h 20 May 2024 23:20:29 -0000 1.5
> +++ sys/arch/octeon/dev/iobusvar.h 27 Apr 2026 09:31:27 -0000
> @@ -36,6 +36,7 @@ extern bus_space_t iobus_tag;
> struct iobus_attach_args {
> char *aa_name;
> int aa_unitno;
> + int aa_node;
>
> bus_addr_t aa_addr;
> int aa_irq;
> Index: sys/arch/octeon/dev/octeon_iobus.c
> ===================================================================
> RCS file: /home/cvs/src/sys/arch/octeon/dev/octeon_iobus.c,v
> diff -u -p -r1.28 octeon_iobus.c
> --- sys/arch/octeon/dev/octeon_iobus.c 20 May 2024 23:17:10 -0000 1.28
> +++ sys/arch/octeon/dev/octeon_iobus.c 27 Apr 2026 09:31:27 -0000
> @@ -231,6 +231,7 @@ iobussearch(struct device *parent, void
> aa.aa_addr = cf->cf_loc[0];
> aa.aa_irq = cf->cf_loc[1];
> aa.aa_unitno = cf->cf_unit;
> + aa.aa_node = 0;
>
> /* No address specified, try to look it up. */
> if (aa.aa_addr == -1) {
> Index: sys/arch/octeon/dev/octpip.c
> ===================================================================
> RCS file: /home/cvs/src/sys/arch/octeon/dev/octpip.c,v
> diff -u -p -r1.3 octpip.c
> --- sys/arch/octeon/dev/octpip.c 8 Sep 2020 13:54:48 -0000 1.3
> +++ sys/arch/octeon/dev/octpip.c 27 Apr 2026 09:31:27 -0000
> @@ -82,6 +82,7 @@ octpip_attach(struct device *parent, str
> iaa.aa_addr = addr;
> iaa.aa_irq = -1;
> iaa.aa_unitno = ifindex;
> + iaa.aa_node = node;
> config_found(self, &iaa, octpip_print);
> }
> }
>
> --
> wbr, Kirill
>
sys/cnmac: read HW address from DTS when available