Subject: kern/27379: flow control support for ex(4)
To: None <gnats-bugs@gnats.NetBSD.org>
From: HITOSHI Osada <QFH02545@nifty.com>
List: netbsd-bugs
Date: 10/23/2004 17:27:58
>Number:         27379
>Category:       kern
>Synopsis:       flow control support for ex(4)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Oct 23 08:29:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     HITOSHI Osada
>Release:        NetBSD 2.99.10 (2004/10/23)
>Organization:
>Environment:
System: NetBSD that 2.99.10 NetBSD 2.99.10 (TIGERMPX) #0: Fri Oct 22 17:43:14 JST 2004 that@that:/sys/arch/i386/compile/TIGERMPX i386
Architecture: i386
Machine: i386

>Description:
	I wrote a patch for ex(4) to support flow control(RXPAUSE only).
	Tested on my TigerMPX(3c920).

>How-To-Repeat:

>Fix:
	Here is a patch. 

Index: elinkxl.c
===================================================================
RCS file: /Sources/NetBSD-rep/netbsd/src/sys/dev/ic/elinkxl.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 elinkxl.c
--- elinkxl.c	30 Sep 2004 07:38:42 -0000	1.1.1.3
+++ elinkxl.c	23 Oct 2004 08:20:40 -0000
@@ -407,7 +407,8 @@
 		ex_set_xcvr(sc, val);
 
 		mii_attach(&sc->sc_dev, &sc->ex_mii, 0xffffffff,
-		    MII_PHY_ANY, MII_OFFSET_ANY, 0);
+		    MII_PHY_ANY, MII_OFFSET_ANY,
+		   (sc->ex_conf & EX_CONF_90XB) ? MIIF_DOPAUSE : 0 );
 		if (LIST_FIRST(&sc->ex_mii.mii_phys) == NULL) {
 			ifmedia_add(&sc->ex_mii.mii_media, IFM_ETHER|IFM_NONE,
 			    0, NULL);
@@ -858,16 +859,18 @@
 	bus_space_tag_t iot = sc->sc_iot;
 	bus_space_handle_t ioh = sc->sc_ioh;
 	u_int32_t configreg;
+	u_int16_t mctl = 0;
 
-	if (((sc->ex_conf & EX_CONF_MII) &&
-	    (sc->ex_mii.mii_media_active & IFM_FDX))
-	    || (!(sc->ex_conf & EX_CONF_MII) &&
-	    (sc->ex_mii.mii_media.ifm_media & IFM_FDX))) {
-		bus_space_write_2(iot, ioh, ELINK_W3_MAC_CONTROL,
-		    MAC_CONTROL_FDX);
+	if (sc->ex_conf & EX_CONF_MII) {
+		if (sc->ex_mii.mii_media_active & IFM_FDX) 
+			mctl |= MAC_CONTROL_FDX;
+		if (sc->ex_flowflags & (IFM_FLOW|IFM_ETH_RXPAUSE))
+			mctl |= ELINK_MAC_FLOWENABLE;
 	} else {
-		bus_space_write_2(iot, ioh, ELINK_W3_MAC_CONTROL, 0);
+		if (sc->ex_mii.mii_media.ifm_media & IFM_FDX)
+			mctl |= MAC_CONTROL_FDX;
 	}
+	bus_space_write_2(iot, ioh, ELINK_W3_MAC_CONTROL, mctl);
 
 	/*
 	 * If the device has MII, select it, and then tell the
@@ -951,7 +954,12 @@
 		if (sc->ex_conf & EX_CONF_MII) {
 			mii_pollstat(&sc->ex_mii);
 			req->ifm_status = sc->ex_mii.mii_media_status;
-			req->ifm_active = sc->ex_mii.mii_media_active;
+			if (sc->ex_conf & EX_CONF_90XB) {
+				req->ifm_active = (sc->ex_mii.mii_media_active & ~IFM_ETH_FMASK) |
+					sc->ex_flowflags;
+			} else {
+				req->ifm_active = sc->ex_mii.mii_media_active;
+			}
 		} else {
 			GO_WINDOW(4);
 			req->ifm_status = IFM_AVALID;
@@ -1379,6 +1387,25 @@
 
 	switch (cmd) {
 	case SIOCSIFMEDIA:
+		if ((sc->ex_conf & EX_CONF_MII) && (sc->ex_conf & EX_CONF_90XB)) {
+			if (IFM_SUBTYPE(ifr->ifr_media) == IFM_AUTO ||
+			    (ifr->ifr_media & IFM_FDX) == 0) {
+				ifr->ifr_media &= ~IFM_ETH_FMASK;
+			}
+			if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) {
+				if ((ifr->ifr_media & IFM_ETH_FMASK) == IFM_FLOW) {
+					/* RXPAUSE only */
+					ifr->ifr_media |= IFM_ETH_RXPAUSE;
+				}
+				if (ifr->ifr_media & IFM_FLOW) {
+					sc->ex_flowflags = 
+						ifr->ifr_media & (IFM_FLOW|IFM_ETH_RXPAUSE);
+				} else {
+					sc->ex_flowflags = 0;
+				}
+			}
+		}
+		/* FALLTHROUGH */
 	case SIOCGIFMEDIA:
 		error = ifmedia_ioctl(ifp, ifr, &sc->ex_mii.mii_media, cmd);
 		break;
@@ -1887,16 +1914,32 @@
 	struct device *v;
 {
 	struct ex_softc *sc = (struct ex_softc *)v;
+	struct mii_data *mii = &sc->ex_mii;
 	bus_space_tag_t iot = sc->sc_iot;
 	bus_space_handle_t ioh = sc->sc_ioh;
-	int mctl;
+	u_int16_t mctl;
+	u_int phy_flowflags;
  
 	GO_WINDOW(3);
 	mctl = bus_space_read_2(iot, ioh, ELINK_W3_MAC_CONTROL);
-	if (sc->ex_mii.mii_media_active & IFM_FDX)
+	if (mii->mii_media_active & IFM_FDX)
 		mctl |= MAC_CONTROL_FDX;
 	else
 		mctl &= ~MAC_CONTROL_FDX;
+	/* 802.3x flow control */
+	if ((sc->ex_conf & EX_CONF_MII) && (sc->ex_conf & EX_CONF_90XB)) {
+		phy_flowflags = mii->mii_media_active & (IFM_FLOW|IFM_ETH_RXPAUSE);
+		mii->mii_media_active &= ~IFM_ETH_FMASK;
+		if ((IFM_SUBTYPE(mii->mii_media.ifm_cur->ifm_media) == IFM_AUTO) &&
+		    (phy_flowflags != sc->ex_flowflags)) {
+			sc->ex_flowflags = phy_flowflags;
+		}
+		if (sc->ex_flowflags & (IFM_FLOW|IFM_ETH_RXPAUSE))
+			mctl |= ELINK_MAC_FLOWENABLE;
+		else
+			mctl &= ~ELINK_MAC_FLOWENABLE;
+	}
+
 	bus_space_write_2(iot, ioh, ELINK_W3_MAC_CONTROL, mctl);
 	GO_WINDOW(1);   /* back to operating window */
 }
Index: elinkxlreg.h
===================================================================
RCS file: /Sources/NetBSD-rep/netbsd/src/sys/dev/ic/elinkxlreg.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- elinkxlreg.h	10 May 2004 09:07:43 -0000	1.1.1.1
+++ elinkxlreg.h	18 Oct 2004 16:12:58 -0000	1.2
@@ -327,3 +327,6 @@
 
 #define EX_UPD_ERR		0x001f4000	/* Errors we check for */
 #define EX_UPD_ERR_VLAN		0x000f0000	/* same for 802.1q */
+
+/* 802.3x flow control flag (in MAC Control Register) */
+#define ELINK_MAC_FLOWENABLE	0x100
Index: elinkxlvar.h
===================================================================
RCS file: /Sources/NetBSD-rep/netbsd/src/sys/dev/ic/elinkxlvar.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- elinkxlvar.h	10 May 2004 09:07:43 -0000	1.1.1.1
+++ elinkxlvar.h	18 Oct 2004 16:12:58 -0000	1.2
@@ -122,6 +122,8 @@
 #if NRND > 0
 	rndsource_element_t rnd_source;
 #endif
+	/* 802.3x flow control (90xB and later, CONF_MII) */
+	int	ex_flowflags;
 
 	/* power management hooks */
 	int (*enable) __P((struct ex_softc *));
>Release-Note:
>Audit-Trail:
>Unformatted: