Module Name:    src
Committed By:   martin
Date:           Sun Nov 10 13:05:15 UTC 2019

Modified Files:
        src/sys/dev/pci [netbsd-9]: if_kse.c

Log Message:
Pull up following revision(s) (requested by nisimura in ticket #406):

        sys/dev/pci/if_kse.c: revision 1.40
        sys/dev/pci/if_kse.c: revision 1.41
        sys/dev/pci/if_kse.c: revision 1.39

comment touchup

 -

clarify 8842 MAC behaves 100FDX only has no alternative media selection
possible.

 -

major rework to fix link control breakage


To generate a diff of this commit:
cvs rdiff -u -r1.38 -r1.38.2.1 src/sys/dev/pci/if_kse.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_kse.c
diff -u src/sys/dev/pci/if_kse.c:1.38 src/sys/dev/pci/if_kse.c:1.38.2.1
--- src/sys/dev/pci/if_kse.c:1.38	Wed May 29 10:07:29 2019
+++ src/sys/dev/pci/if_kse.c	Sun Nov 10 13:05:15 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_kse.c,v 1.38 2019/05/29 10:07:29 msaitoh Exp $	*/
+/*	$NetBSD: if_kse.c,v 1.38.2.1 2019/11/10 13:05:15 martin Exp $	*/
 
 /*-
  * Copyright (c) 2006 The NetBSD Foundation, Inc.
@@ -29,9 +29,12 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_kse.c,v 1.38 2019/05/29 10:07:29 msaitoh Exp $");
+/*
+ * Micrel 8841/8842 10/100 ethernet driver
+ */
 
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: if_kse.c,v 1.38.2.1 2019/11/10 13:05:15 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -58,6 +61,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_kse.c,v 1
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcidevs.h>
 
+#define KSE_LINKDEBUG 0
+
 #define CSR_READ_4(sc, off) \
 	    bus_space_read_4(sc->sc_st, sc->sc_sh, off)
 #define CSR_WRITE_4(sc, off, val) \
@@ -93,6 +98,17 @@ __KERNEL_RCSID(0, "$NetBSD: if_kse.c,v 1
 #define P1SR	0x514	/* port 1 status */
 #define P2CR4	0x532	/* port 2 control 4 */
 #define P2SR	0x534	/* port 2 status */
+#define PxCR_STARTNEG	(1U << 9)	/* restart auto negotiation */
+#define PxCR_AUTOEN	(1U << 7)	/* auto negotiation enable */
+#define PxCR_SPD100	(1U << 6)	/* force speed 100 */
+#define PxCR_USEFDX	(1U << 5)	/* force full duplex */
+#define PxCR_USEFC	(1U << 4)	/* advertise pause flow control */
+#define PxSR_ACOMP	(1U << 6)	/* auto negotiation completed */
+#define PxSR_SPD100	(1U << 10)	/* speed is 100Mbps */
+#define PxSR_FDX	(1U << 9)	/* full duplex */
+#define PxSR_LINKUP	(1U << 5)	/* link is good */
+#define PxSR_RXFLOW	(1U << 12)	/* receive flow control active */
+#define PxSR_TXFLOW	(1U << 11)	/* transmit flow control active */
 
 #define TXC_BS_MSK	0x3f000000	/* burst size */
 #define TXC_BS_SFT	(24)		/* 1,2,4,8,16,32 or 0 for unlimited */
@@ -207,8 +223,8 @@ struct kse_softc {
 	void *sc_ih;			/* interrupt cookie */
 
 	struct ifmedia sc_media;	/* ifmedia information */
-	int sc_media_status;		/* PHY */
-	int sc_media_active;		/* PHY */
+	int sc_linkstatus;		/* last P1SR register value */
+
 	callout_t  sc_callout;		/* MII tick callout */
 	callout_t  sc_stat_ch;		/* statistics counter callout */
 
@@ -313,11 +329,10 @@ static int kse_intr(void *);
 static void rxintr(struct kse_softc *);
 static void txreap(struct kse_softc *);
 static void lnkchg(struct kse_softc *);
-static int ifmedia_upd(struct ifnet *);
-static void ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int ksephy_change(struct ifnet *);
+static void ksephy_status(struct ifnet *, struct ifmediareq *);
+static void nopifm_status(struct ifnet *, struct ifmediareq *);
 static void phy_tick(void *);
-static int ifmedia2_upd(struct ifnet *);
-static void ifmedia2_sts(struct ifnet *, struct ifmediareq *);
 #ifdef KSE_EVENT_COUNTERS
 static void stat_tick(void *);
 static void zerostats(struct kse_softc *);
@@ -493,8 +508,9 @@ kse_attach(device_t parent, device_t sel
 	/* Initialize ifmedia structures. */
 	ifm = &sc->sc_media;
 	sc->sc_ethercom.ec_ifmedia = ifm;
+	sc->sc_linkstatus = 0;
 	if (sc->sc_chip == 0x8841) {
-		ifmedia_init(ifm, 0, ifmedia_upd, ifmedia_sts);
+		ifmedia_init(ifm, 0, ksephy_change, ksephy_status);
 		ifmedia_add(ifm, IFM_ETHER | IFM_10_T, 0, NULL);
 		ifmedia_add(ifm, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
 		ifmedia_add(ifm, IFM_ETHER | IFM_100_TX, 0, NULL);
@@ -502,9 +518,18 @@ kse_attach(device_t parent, device_t sel
 		ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL);
 		ifmedia_set(ifm, IFM_ETHER | IFM_AUTO);
 	} else {
-		ifmedia_init(ifm, 0, ifmedia2_upd, ifmedia2_sts);
-		ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL);
-		ifmedia_set(ifm, IFM_ETHER | IFM_AUTO);
+		/*
+		 * pretend 100FDX w/ no alternative media selection.
+		 * 8842 MAC is tied with a builtin 3 port switch.
+		 * It can do rate control over either of tx / rx direction
+		 * respectively, tough, this driver leaves the rate unlimited
+		 * intending 100Mbps maximum.
+		 * 2 ports behave in AN mode and this driver provides no mean
+		 * to see the exact details.
+		 */
+		ifmedia_init(ifm, 0, NULL, nopifm_status);
+		ifmedia_add(ifm, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
+		ifmedia_set(ifm, IFM_ETHER | IFM_100_TX | IFM_FDX);
 	}
 
 	printf("%s: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto\n",
@@ -522,7 +547,7 @@ kse_attach(device_t parent, device_t sel
 	IFQ_SET_READY(&ifp->if_snd);
 
 	/*
-	 * KSZ8842 can handle 802.1Q VLAN-sized frames,
+	 * capable of 802.1Q VLAN-sized frames,
 	 * can do IPv4, TCPv4, and UDPv4 checksums in hardware.
 	 */
 	sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
@@ -766,7 +791,8 @@ kse_init(struct ifnet *ifp)
 	kse_set_filter(sc);
 
 	/* set current media */
-	(void)ifmedia_upd(ifp);
+	if (sc->sc_chip == 0x8841)
+		(void)ksephy_change(ifp);
 
 	/* enable transmitter and receiver */
 	CSR_WRITE_4(sc, MDTXC, sc->sc_txc);
@@ -1257,92 +1283,92 @@ lnkchg(struct kse_softc *sc)
 {
 	struct ifmediareq ifmr;
 
-#if 0 /* rambling link status */
-	printf("%s: link %s\n", device_xname(sc->sc_dev),
-	    (CSR_READ_2(sc, P1SR) & (1U << 5)) ? "up" : "down");
+#if KSE_LINKDEBUG > 0
+printf("link change detected\n");
 #endif
-	ifmedia_sts(&sc->sc_ethercom.ec_if, &ifmr);
+	ksephy_status(&sc->sc_ethercom.ec_if, &ifmr);
 }
 
 static int
-ifmedia_upd(struct ifnet *ifp)
+ksephy_change(struct ifnet *ifp)
 {
 	struct kse_softc *sc = ifp->if_softc;
 	struct ifmedia *ifm = &sc->sc_media;
-	uint16_t ctl;
-
-	ctl = 0;
-	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
-		ctl |= (1U << 13); /* Restart AN */
-		ctl |= (1U << 7);  /* Enable AN */
-		ctl |= (1U << 4);  /* Advertise flow control pause */
-		ctl |= (1U << 3) | (1U << 2) | (1U << 1) | (1U << 0);
-	}
-	else {
-		if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX)
-			ctl |= (1U << 6);
+	uint16_t p1cr4;
+#if KSE_LINKDEBUG > 0
+printf("ifm_media: %x\n", ifm->ifm_cur->ifm_media);
+#endif
+	p1cr4 = 0;
+	if (IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_AUTO) {
+		p1cr4 |= PxCR_STARTNEG;	/* restart AN */
+		p1cr4 |= PxCR_AUTOEN;	/* enable AN */
+		p1cr4 |= PxCR_USEFC;	/* advertise flow control pause */
+		p1cr4 |= 0xf;		/* advertise 100-FDX,100-HDX,10-FDX,10-HDX */
+	} else {
+		if (IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_100_TX)
+			p1cr4 |= PxCR_SPD100;
 		if (ifm->ifm_media & IFM_FDX)
-			ctl |= (1U << 5);
+			p1cr4 |= PxCR_USEFDX;
 	}
-	CSR_WRITE_2(sc, P1CR4, ctl);
-
-	sc->sc_media_active = IFM_NONE;
-	sc->sc_media_status = IFM_AVALID;
-
+	CSR_WRITE_2(sc, P1CR4, p1cr4);
+#if KSE_LINKDEBUG > 0
+printf("P1CR4: %04x\n", p1cr4);
+#endif
 	return 0;
 }
 
 static void
-ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+ksephy_status(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
 	struct kse_softc *sc = ifp->if_softc;
-	struct ifmedia *ifm = &sc->sc_media;
-	uint16_t ctl, sts, result;
-
-	ifmr->ifm_status = IFM_AVALID;
-	ifmr->ifm_active = IFM_ETHER;
-
-	ctl = CSR_READ_2(sc, P1CR4);
-	sts = CSR_READ_2(sc, P1SR);
-	if ((sts & (1U << 5)) == 0) {
-		ifmr->ifm_active |= IFM_NONE;
-		goto out; /* Link is down */
-	}
-	ifmr->ifm_status |= IFM_ACTIVE;
-	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
-		if ((sts & (1U << 6)) == 0) {
-			ifmr->ifm_active |= IFM_NONE;
+	int media_status;
+	u_int media_active;
+	uint16_t p1cr4, p1sr;
+
+	media_status = IFM_AVALID;
+	media_active = IFM_ETHER;
+
+	p1cr4 = CSR_READ_2(sc, P1CR4);
+	p1sr = CSR_READ_2(sc, P1SR);
+#if KSE_LINKDEBUG > 0
+printf("P1SR: %04x link %s\n", p1sr, (p1sr & PxSR_LINKUP) ? "up" : "down");
+#endif
+	sc->sc_linkstatus = p1sr;
+	if (p1sr & PxSR_LINKUP)
+		media_status |= IFM_ACTIVE;
+
+	if (p1cr4 & PxCR_AUTOEN) {
+		if ((p1sr & PxSR_ACOMP) == 0) {
+			media_active |= IFM_NONE;
 			goto out; /* Negotiation in progress */
 		}
-		result = ctl & sts & 017;
-		if (result & (1U << 3))
-			ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
-		else if (result & (1U << 2))
-			ifmr->ifm_active |= IFM_100_TX | IFM_HDX;
-		else if (result & (1U << 1))
-			ifmr->ifm_active |= IFM_10_T | IFM_FDX;
-		else if (result & (1U << 0))
-			ifmr->ifm_active |= IFM_10_T | IFM_HDX;
-		else
-			ifmr->ifm_active |= IFM_NONE;
-		if (ctl & (1U << 4))
-			ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
-		if (sts & (1U << 4))
-			ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
-	}
-	else {
-		ifmr->ifm_active |= (sts & (1U << 10)) ? IFM_100_TX : IFM_10_T;
-		if (sts & (1U << 9))
-			ifmr->ifm_active |= IFM_FDX;
-		if (sts & (1U << 12))
-			ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
-		if (sts & (1U << 11))
-			ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
 	}
 
+	media_active |= (p1sr & PxSR_SPD100) ? IFM_100_TX : IFM_10_T;
+	if (p1sr & PxSR_FDX)
+		media_active |= IFM_FDX;
+	if (p1sr & PxSR_RXFLOW)
+		media_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
+	if (p1sr & PxSR_TXFLOW)
+		media_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
   out:
-	sc->sc_media_status = ifmr->ifm_status;
-	sc->sc_media_active = ifmr->ifm_active;
+	ifmr->ifm_active = media_active;
+	ifmr->ifm_status = media_status;
+}
+
+static void
+nopifm_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct kse_softc *sc = ifp->if_softc;
+	struct ifmedia *ifm = &sc->sc_media;
+
+#if KSE_LINKDEBUG > 1
+printf("p1sr: %04x, p2sr: %04x\n", CSR_READ_2(sc, P1SR), CSR_READ_2(sc, P2SR));
+#endif
+
+	/* 8842 MAC pretends 100FDX all the time */
+	ifmr->ifm_active = ifm->ifm_cur->ifm_media;
+	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
 }
 
 static void
@@ -1351,46 +1377,17 @@ phy_tick(void *arg)
 	struct kse_softc *sc = arg;
 	struct ifmediareq ifmr;
 	int s;
+	uint16_t p1sr;
 
 	s = splnet();
-	ifmedia_sts(&sc->sc_ethercom.ec_if, &ifmr);
+	p1sr = CSR_READ_2(sc, P1SR);
+	if (sc->sc_linkstatus != p1sr)
+		ksephy_status(&sc->sc_ethercom.ec_if, &ifmr);
 	splx(s);
 
 	callout_reset(&sc->sc_callout, hz, phy_tick, sc);
 }
 
-static int
-ifmedia2_upd(struct ifnet *ifp)
-{
-	struct kse_softc *sc = ifp->if_softc;
-
-	sc->sc_media_status = IFM_AVALID;
-	sc->sc_media_active = IFM_NONE;
-	return 0;
-}
-
-static void
-ifmedia2_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
-{
-	struct kse_softc *sc = ifp->if_softc;
-	int p1sts, p2sts;
-
-	ifmr->ifm_status = IFM_AVALID;
-	ifmr->ifm_active = IFM_ETHER;
-	p1sts = CSR_READ_2(sc, P1SR);
-	p2sts = CSR_READ_2(sc, P2SR);
-	if (((p1sts | p2sts) & (1U << 5)) == 0)
-		ifmr->ifm_active |= IFM_NONE;
-	else {
-		ifmr->ifm_status |= IFM_ACTIVE;
-		ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
-		ifmr->ifm_active |= IFM_FLOW
-		    | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE;
-	}
-	sc->sc_media_status = ifmr->ifm_status;
-	sc->sc_media_active = ifmr->ifm_active;
-}
-
 #ifdef KSE_EVENT_COUNTERS
 static void
 stat_tick(void *arg)

Reply via email to