Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
Re: sys/cnmac: support CN71xx 1000BASE-X ports
To:
Visa Hankala <visa@hankala.org>
Cc:
tech@openbsd.org
Date:
Wed, 22 Apr 2026 01:13:26 +0200

Download raw body.

Thread
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.

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