Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 May 2017 08:24:23 +0000 (UTC)
From:      Wojciech Macek <wma@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r318524 - head/sys/dev/etherswitch/e6000sw
Message-ID:  <201705190824.v4J8ON6X007271@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: wma
Date: Fri May 19 08:24:23 2017
New Revision: 318524
URL: https://svnweb.freebsd.org/changeset/base/318524

Log:
  Poll PHY status using internal e6000sw registers
  
  e6000sw family automatically reflects PHY status in each port's registers.
  Therefore it is not necessary to do a full PHY polling squence, which
  results in much quicker operation and much less significant usage of
  the SMI bus.
  
  Care must be taken that the resulting ifmedia_active is identical to
  what the PHY will compute, or gratuitous link status changes will
  occur whenever the PHYs update function is called.
  
  This patch implements above improvement. On the occasion set a pointer to
  the proc structure to be part of software context instead of being
  a global variable.
  
  Submitted by: Marcin Wojtas <mw@semihalf.com>
  Obtained from: Semihalf
  Sponsored by: Stormshield
  Reviewed by: loos
  Differential revision: https://reviews.freebsd.org/D10714

Modified:
  head/sys/dev/etherswitch/e6000sw/e6000sw.c
  head/sys/dev/etherswitch/e6000sw/e6000swreg.h

Modified: head/sys/dev/etherswitch/e6000sw/e6000sw.c
==============================================================================
--- head/sys/dev/etherswitch/e6000sw/e6000sw.c	Fri May 19 08:19:51 2017	(r318523)
+++ head/sys/dev/etherswitch/e6000sw/e6000sw.c	Fri May 19 08:24:23 2017	(r318524)
@@ -89,7 +89,7 @@ typedef struct e6000sw_softc {
 	char			*ifname[E6000SW_MAX_PORTS];
 	device_t		miibus[E6000SW_MAX_PORTS];
 	struct mii_data		*mii[E6000SW_MAX_PORTS];
-	struct callout		tick_callout;
+	struct proc		*kproc;
 
 	uint32_t		cpuports_mask;
 	uint32_t		fixed_mask;
@@ -149,8 +149,6 @@ static __inline int e6000sw_is_phyport(e
 static __inline struct mii_data *e6000sw_miiforphy(e6000sw_softc_t *sc,
     unsigned int phy);
 
-static struct proc *e6000sw_kproc;
-
 static device_method_t e6000sw_methods[] = {
 	/* device interface */
 	DEVMETHOD(device_identify,		e6000sw_identify),
@@ -419,8 +417,7 @@ e6000sw_attach(device_t dev)
 	bus_generic_probe(dev);
 	bus_generic_attach(dev);
 
-	kproc_create(e6000sw_tick, sc, &e6000sw_kproc, 0, 0,
-	    "e6000sw tick kproc");
+	kproc_create(e6000sw_tick, sc, &sc->kproc, 0, 0, "e6000sw tick kproc");
 
 	return (0);
 
@@ -1010,23 +1007,65 @@ e6000sw_get_pvid(e6000sw_softc_t *sc, in
 	return (0);
 }
 
+/*
+ * Convert port status to ifmedia.
+ */
+static void
+e6000sw_update_ifmedia(uint16_t portstatus, u_int *media_status, u_int *media_active)
+{
+	*media_active = IFM_ETHER;
+	*media_status = IFM_AVALID;
+
+	if ((portstatus & PORT_STATUS_LINK_MASK) != 0)
+		*media_status |= IFM_ACTIVE;
+	else {
+		*media_active |= IFM_NONE;
+		return;
+	}
+
+	switch (portstatus & PORT_STATUS_SPEED_MASK) {
+	case PORT_STATUS_SPEED_10:
+		*media_active |= IFM_10_T;
+		break;
+	case PORT_STATUS_SPEED_100:
+		*media_active |= IFM_100_TX;
+		break;
+	case PORT_STATUS_SPEED_1000:
+		*media_active |= IFM_1000_T;
+		break;
+	}
+
+	if ((portstatus & PORT_STATUS_DUPLEX_MASK) == 0)
+		*media_active |= IFM_FDX;
+	else
+		*media_active |= IFM_HDX;
+}
+
 static void
 e6000sw_tick (void *arg)
 {
 	e6000sw_softc_t *sc;
 	struct mii_softc *miisc;
+	uint16_t portstatus;
 	int port;
 
 	sc = arg;
 
 	E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
+
 	for (;;) {
 		E6000SW_LOCK(sc);
 		for (port = 0; port < sc->num_ports; port++) {
 			/* Tick only on PHY ports */
 			if (!e6000sw_is_phyport(sc, port))
 				continue;
-			mii_tick(sc->mii[port]);
+
+			portstatus = e6000sw_readreg(sc, REG_PORT(port), PORT_STATUS);
+
+			e6000sw_update_ifmedia(portstatus,
+			    &sc->mii[port]->mii_media_status,
+			    &sc->mii[port]->mii_media_active);
+
 			LIST_FOREACH(miisc, &sc->mii[port]->mii_phys, mii_list) {
 				if (IFM_INST(sc->mii[port]->mii_media.ifm_cur->ifm_media)
 				    != miisc->mii_inst)

Modified: head/sys/dev/etherswitch/e6000sw/e6000swreg.h
==============================================================================
--- head/sys/dev/etherswitch/e6000sw/e6000swreg.h	Fri May 19 08:19:51 2017	(r318523)
+++ head/sys/dev/etherswitch/e6000sw/e6000swreg.h	Fri May 19 08:24:23 2017	(r318524)
@@ -55,6 +55,14 @@ struct atu_opt {
  * Per-Port Switch Registers
  */
 #define PORT_STATUS			0x0
+#define	PORT_STATUS_SPEED_MASK		0x300
+#define	PORT_STATUS_SPEED_10		0
+#define	PORT_STATUS_SPEED_100		1
+#define	PORT_STATUS_SPEED_1000		2
+#define	PORT_STATUS_DUPLEX_MASK		(1 << 10)
+#define	PORT_STATUS_LINK_MASK		(1 << 11)
+#define	PORT_STATUS_PHY_DETECT_MASK	(1 << 12)
+
 #define PSC_CONTROL			0x1
 #define SWITCH_ID			0x3
 #define PORT_CONTROL			0x4



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201705190824.v4J8ON6X007271>