Download raw body.
sys/cnmac: support CN71xx 1000BASE-X ports
On Wed, Apr 22, 2026 at 01:13:26AM +0200, Kirill A. Korinsky wrote:
> On Tue, 21 Apr 2026 18:09:59 +0200,
> Visa Hankala <visa@hankala.org> 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.
Indeed, making the switch functional is a separate thing. Some
detective work is needed if the device tree does not indicate how
the switch control interface is connected to the OCTEON SoC.
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.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
sys/cnmac: support CN71xx 1000BASE-X ports