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>