From: Kirill A. Korinsky Subject: Re: sys/cnmac: support CN71xx 1000BASE-X ports To: Visa Hankala Cc: tech@openbsd.org Date: Wed, 22 Apr 2026 01:13:26 +0200 On Tue, 21 Apr 2026 18:09:59 +0200, Visa Hankala wrote: > > > + for (child = OF_child(node); child != 0; child = OF_peer(child)) { > > + if (!OF_is_compatible(child, "cavium,octeon-3860-pip-port")) > > + continue; > > + reg = OF_getpropint(child, "reg", -1); > > + if (reg < 0 || reg >= nitems(sc->sc_port_types)) > > + continue; > > + > > + sc->sc_port_types[reg] = GMX_SGMII_PORT; > > If I read this correctly, this uses SGMII mode regardless of the > actual port mode. I think this port type setting should be conditional > to the cavium,sgmii-mac-1000x-mode property. > > However, does the INF_MODE logic give an incorrect result with your > hardware? > I've tried: if (0 && cn30xxgmx_init_cn71xx(sc) == 0) break; and no, it doesn't work. It picks interface@4/ethernet@0 as cnmac0 and it doesn't work. Actually I not sure that to do with interface@1/ethernet@0 which has sgmii-mac-phy-mode and no phy in DTS. But uboot reports that: PCIe: Port 0 link active, 1 lanes, speed gen2 PCIe: Link timeout on port 1, probably the slot is empty PCIe: Port 2 not in PCIe mode, skipping Net: octeth0 Interface 0 has 1 ports (SGMII) which is interface@0/ethernet@0 whith sgmii-mac-1000x-mode. > > @@ -1382,6 +1444,8 @@ cn30xxgmx_sgmii_speed(struct cn30xxgmx_p > > > > misc_ctl = PCS_READ_8(sc, PCS_MISC_CTL); > > CLR(misc_ctl, PCS_MISC_CTL_SAMP_PT); > > + if (sc->sc_port_disable_an) > > + SET(misc_ctl, PCS_MISC_CTL_AN_OVRD); > > I wonder if this should set (or clear) the PCS_MISC_CTL_MODE bit if > the SGMII MAC mode is enabled (or not). Would this help with the > hardware initialization during boot? > I have checked Linux and FreeBSD-13, and they both do not toggle PCS_MISC_CTL_MODE to switch between SGMII MAC mode and 1000BASE-X. I had played with that and interface@1/ethernet@0, but can't figure out how to make it works, so, for now I'd like to have minimal diff which is attached and address your remakrs, and which allows to initialize cnmac0 which somehow works if the switch was initialized in uboot via dhcp. Index: sys/arch/octeon/dev/cn30xxgmx.c =================================================================== RCS file: /home/cvs/src/sys/arch/octeon/dev/cn30xxgmx.c,v diff -u -p -r1.55 cn30xxgmx.c --- sys/arch/octeon/dev/cn30xxgmx.c 8 Jul 2024 08:07:45 -0000 1.55 +++ sys/arch/octeon/dev/cn30xxgmx.c 21 Apr 2026 22:28:32 -0000 @@ -169,22 +169,64 @@ cn30xxgmx_match(struct device *parent, v } int -cn30xxgmx_get_phy_phandle(int interface, int port) +cn30xxgmx_get_phy_phandle(int interface, int port, int *port_1000x, + int *disable_an) { char name[64]; int node; int phandle = 0; + if (port_1000x != NULL) + *port_1000x = 0; + if (disable_an != NULL) + *disable_an = 0; + snprintf(name, sizeof(name), "/soc/pip@11800a0000000/interface@%x/ethernet@%x", interface, port); node = OF_finddevice(name); - if (node != - 1) + if (node != -1) { phandle = OF_getpropint(node, "phy-handle", 0); + if (port_1000x != NULL) { + *port_1000x = OF_getproplen(node, + "cavium,sgmii-mac-1000x-mode") >= 0; + } + if (disable_an != NULL) { + *disable_an = OF_getproplen(node, + "cavium,disable-autonegotiation") >= 0; + } + } return phandle; } void +cn30xxgmx_init_cn71xx(struct cn30xxgmx_softc *sc) +{ + char name[64]; + int child, node, reg; + + snprintf(name, sizeof(name), + "/soc/pip@11800a0000000/interface@%x", sc->sc_unitno); + node = OF_finddevice(name); + if (node == -1) + return; + + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + if (!OF_is_compatible(child, "cavium,octeon-3860-pip-port")) + continue; + if (OF_getproplen(child, "cavium,sgmii-mac-1000x-mode") < 0) + continue; + reg = OF_getpropint(child, "reg", -1); + if (reg < 0 || reg >= nitems(sc->sc_port_types)) + continue; + + sc->sc_port_types[reg] = GMX_SGMII_PORT; + if (sc->sc_nports < reg + 1) + sc->sc_nports = reg + 1; + } +} + +void cn30xxgmx_attach(struct device *parent, struct device *self, void *aux) { struct cn30xxgmx_attach_args gmx_aa; @@ -193,6 +235,7 @@ cn30xxgmx_attach(struct device *parent, struct cn30xxgmx_softc *sc = (void *)self; struct cn30xxsmi_softc *smi; int i; + int phandle; int phy_addr; int port; int status; @@ -224,15 +267,20 @@ cn30xxgmx_attach(struct device *parent, printf("\n"); for (i = 0; i < sc->sc_nports; i++) { + port_sc = &sc->sc_ports[i]; if (sc->sc_port_types[i] == GMX_AGL_PORT) port = 24; else port = GMX_PORT_NUM(sc->sc_unitno, i); - if (cn30xxsmi_get_phy(cn30xxgmx_get_phy_phandle(sc->sc_unitno, - i), port, &smi, &phy_addr)) + phandle = cn30xxgmx_get_phy_phandle(sc->sc_unitno, i, + &port_sc->sc_port_1000x, + &port_sc->sc_port_disable_an); + smi = NULL; + phy_addr = -1; + if (!(port_sc->sc_port_1000x && phandle == 0) && + cn30xxsmi_get_phy(phandle, port, &smi, &phy_addr)) continue; - port_sc = &sc->sc_ports[i]; port_sc->sc_port_gmx = sc; port_sc->sc_port_no = port; port_sc->sc_port_type = sc->sc_port_types[i]; @@ -421,6 +469,10 @@ cn30xxgmx_init(struct cn30xxgmx_softc *s break; } + cn30xxgmx_init_cn71xx(sc); + if (sc->sc_nports != 0) + break; + inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh, GMX0_INF_MODE); if ((inf_mode & INF_MODE_EN) == 0) @@ -1341,6 +1393,17 @@ cn30xxgmx_sgmii_enable(struct cn30xxgmx_ return 1; } + if (sc->sc_port_disable_an) { + CLR(ctl_reg, PCS_MR_CONTROL_AN_EN); + CLR(ctl_reg, PCS_MR_CONTROL_RST_AN); + CLR(ctl_reg, PCS_MR_CONTROL_PWR_DN); + CLR(ctl_reg, PCS_MR_CONTROL_SPDLSB); + SET(ctl_reg, PCS_MR_CONTROL_SPDMSB); + SET(ctl_reg, PCS_MR_CONTROL_DUPLEX); + PCS_WRITE_8(sc, PCS_MR_CONTROL, ctl_reg); + return 0; + } + /* Start a new SGMII autonegotiation. */ SET(ctl_reg, PCS_MR_CONTROL_AN_EN); SET(ctl_reg, PCS_MR_CONTROL_RST_AN); @@ -1382,6 +1445,8 @@ cn30xxgmx_sgmii_speed(struct cn30xxgmx_p misc_ctl = PCS_READ_8(sc, PCS_MISC_CTL); CLR(misc_ctl, PCS_MISC_CTL_SAMP_PT); + if (sc->sc_port_disable_an) + SET(misc_ctl, PCS_MISC_CTL_AN_OVRD); /* Disable the GMX port if the link is down. */ if (cn30xxgmx_link_status(sc)) Index: sys/arch/octeon/dev/cn30xxgmxvar.h =================================================================== RCS file: /home/cvs/src/sys/arch/octeon/dev/cn30xxgmxvar.h,v diff -u -p -r1.14 cn30xxgmxvar.h --- sys/arch/octeon/dev/cn30xxgmxvar.h 20 May 2024 23:13:33 -0000 1.14 +++ sys/arch/octeon/dev/cn30xxgmxvar.h 21 Apr 2026 21:16:43 -0000 @@ -61,6 +61,8 @@ struct cn30xxgmx_port_softc { bus_space_handle_t sc_port_regh; int sc_port_no; /* GMX0:0, GMX0:1, ... */ int sc_port_type; + int sc_port_1000x; + int sc_port_disable_an; uint64_t sc_link; struct mii_data *sc_port_mii; struct arpcom *sc_port_ac; 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.87 if_cnmac.c --- sys/arch/octeon/dev/if_cnmac.c 21 Apr 2026 20:20:09 -0000 1.87 +++ sys/arch/octeon/dev/if_cnmac.c 21 Apr 2026 22:23:05 -0000 @@ -482,6 +482,19 @@ cnmac_mediainit(struct cnmac_softc *sc) ifmedia_init(&sc->sc_mii.mii_media, 0, cnmac_mediachange, cnmac_mediastatus); + if (sc->sc_gmx_port->sc_port_1000x) { + ifmedia_add(&sc->sc_mii.mii_media, + IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); + ifmedia_set(&sc->sc_mii.mii_media, + IFM_ETHER | IFM_1000_T | IFM_FDX); + sc->sc_mii.mii_media_status = IFM_AVALID | IFM_ACTIVE; + sc->sc_mii.mii_media_active = + IFM_ETHER | IFM_1000_T | IFM_FDX; + ifp->if_baudrate = IF_Gbps(1); + ifp->if_link_state = LINK_STATE_FULL_DUPLEX; + return 0; + } + mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, sc->sc_phy_addr, MII_OFFSET_ANY, MIIF_DOPAUSE); @@ -503,6 +516,14 @@ cnmac_mediastatus(struct ifnet *ifp, str { struct cnmac_softc *sc = ifp->if_softc; + if (sc->sc_gmx_port->sc_port_1000x) { + ifmr->ifm_status = sc->sc_mii.mii_media_status; + ifmr->ifm_active = (sc->sc_mii.mii_media_active & + ~IFM_ETH_FMASK) | + sc->sc_gmx_port->sc_port_flowflags; + return; + } + mii_pollstat(&sc->sc_mii); ifmr->ifm_status = sc->sc_mii.mii_media_status; ifmr->ifm_active = sc->sc_mii.mii_media_active; @@ -514,6 +535,9 @@ int cnmac_mediachange(struct ifnet *ifp) { struct cnmac_softc *sc = ifp->if_softc; + + if (sc->sc_gmx_port->sc_port_1000x) + return 0; if ((ifp->if_flags & IFF_UP) == 0) return 0; -- wbr, Kirill