Index: sys/dev/usb/if_axe.c =================================================================== --- sys/dev/usb/if_axe.c (revision 183560) +++ sys/dev/usb/if_axe.c (working copy) @@ -162,6 +162,7 @@ static miibus_writereg_t axe_miibus_writereg; static miibus_statchg_t axe_miibus_statchg; +static int axe_get_phyno(struct axe_softc *, int); static int axe_encap(struct axe_softc *, struct mbuf *, int); static void axe_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status); static void axe_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status); @@ -248,21 +249,10 @@ return(0); AXE_SLEEPLOCKASSERT(sc); -#ifdef notdef - /* - * The chip tells us the MII address of any supported - * PHYs attached to the chip, so only read from those. - */ - if (sc->axe_phyaddrs[0] != AXE_NOPHY && phy != sc->axe_phyaddrs[0]) + if (sc->axe_phyno != phy) return (0); - if (sc->axe_phyaddrs[1] != AXE_NOPHY && phy != sc->axe_phyaddrs[1]) - return (0); -#endif - if (sc->axe_phyaddrs[0] != 0xFF && sc->axe_phyaddrs[0] != phy) - return (0); - AXE_LOCK(sc); axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, (void *)&val); @@ -274,9 +264,6 @@ return(-1); } - if (val && val != 0xffff) - sc->axe_phyaddrs[0] = phy; - return (le16toh(val)); } @@ -290,6 +277,10 @@ return(0); AXE_SLEEPLOCKASSERT(sc); + + if (sc->axe_phyno != phy) + return (0); + AXE_LOCK(sc); axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); val = htole32(val); @@ -310,12 +301,43 @@ { struct axe_softc *sc = device_get_softc(dev); struct mii_data *mii = GET_MII(sc); + struct ifnet *ifp; int val, err; - val = (mii->mii_media_active & IFM_GMASK) == IFM_FDX ? - AXE_MEDIA_FULL_DUPLEX : 0; + ifp = sc->axe_ifp; + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + sc->axe_link = 0; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + case IFM_100_TX: + sc->axe_link++; + break; + case IFM_1000_T: + if ((sc->axe_flags & AX178) == 0) + break; + sc->axe_link++; + break; + default: + break; + } + } + + /* Lost link, do nothing. */ + if (sc->axe_link == 0) + return; + + val = 0; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + val |= AXE_MEDIA_FULL_DUPLEX; if (sc->axe_flags & (AX178|AX772)) { val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; + if (sc->axe_flags & AX178) + val |= AXE_178_MEDIA_ENCK; switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_1000_T: @@ -343,7 +365,6 @@ struct axe_softc *sc = ifp->if_softc; struct mii_data *mii = GET_MII(sc); - sc->axe_link = 0; if (mii->mii_instance) { struct mii_softc *miisc; LIST_FOREACH(miisc, &mii->mii_phys, mii_list) @@ -456,6 +477,9 @@ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); usbd_delay_ms(sc->axe_udev, 150); + /* Enable MII/GMII/RGMII interface to work with external PHY. */ + axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); + usbd_delay_ms(sc->axe_udev, 150); axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); } @@ -465,7 +489,7 @@ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); usbd_delay_ms(sc->axe_udev, 40); - if (sc->axe_phyaddrs[1] == AXE_INTPHY) { + if (sc->axe_phyno == AXE_PHY_NO_AX772_EPHY) { /* ask for embedded PHY */ axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL); usbd_delay_ms(sc->axe_udev, 10); @@ -516,6 +540,30 @@ return; } +static int +axe_get_phyno(struct axe_softc *sc, int sel) +{ + int phyno; + + phyno = -1; + switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) { + case PHY_TYPE_100_HOME: + case PHY_TYPE_GIG: + phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]); + break; + case PHY_TYPE_SPECIAL: + /* FALLTHROUGH */ + case PHY_TYPE_RSVD: + /* FALLTHROUGH */ + case PHY_TYPE_NON_SUP: + /* FALLTHROUGH */ + default: + break; + } + + return (phyno); +} + /* * Probe for a AX88172 chip. */ @@ -610,6 +658,14 @@ /* We need the PHYID for the init dance in some cases */ axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs); + sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); + if (sc->axe_phyno == -1) + sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); + if (sc->axe_phyno == -1) { + device_printf(sc->axe_dev, + "no valid PHY address found, assuming PHY address 0\n"); + sc->axe_phyno = 0; + } if (sc->axe_flags & AX178) axe_ax88178_init(sc); @@ -629,12 +685,6 @@ */ axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, (void *)&sc->axe_ipgs); - /* - * Work around broken adapters that appear to lie about - * their PHY addresses. - */ - sc->axe_phyaddrs[0] = sc->axe_phyaddrs[1] = 0xFF; - ifp = sc->axe_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(sc->axe_dev, "can not if_alloc()\n"); @@ -999,12 +1049,8 @@ } mii_tick(mii); - if (!sc->axe_link && mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - sc->axe_link++; - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - axe_start(ifp); - } + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + axe_start(ifp); sc->axe_stat_ch = timeout(axe_tick, sc, hz); @@ -1122,6 +1168,7 @@ { struct axe_softc *sc = xsc; struct ifnet *ifp = sc->axe_ifp; + struct mii_data *mii = GET_MII(sc); struct axe_chain *c; usbd_status err; int i; @@ -1223,6 +1270,9 @@ usbd_transfer(c->axe_xfer); } + sc->axe_link = 0; + mii_mediachg(mii); + ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; Index: sys/dev/usb/if_axereg.h =================================================================== --- sys/dev/usb/if_axereg.h (revision 183560) +++ sys/dev/usb/if_axereg.h (working copy) @@ -134,9 +134,24 @@ #define AXE_178_RXCMD_MFB_8192 0x0200 /* 8K max frame burst */ #define AXE_178_RXCMD_MFB_16384 0x0300 /* 16K max frame burst*/ -#define AXE_NOPHY 0xE0 -#define AXE_INTPHY 0x10 +#define AXE_PHY_SEL_PRI 1 +#define AXE_PHY_SEL_SEC 0 +#define AXE_PHY_TYPE_MASK 0xE0 +#define AXE_PHY_TYPE_SHIFT 5 +#define AXE_PHY_TYPE(x) \ + (((x) & AXE_PHY_TYPE_MASK) >> AXE_PHY_TYPE_SHIFT) +#define PHY_TYPE_100_HOME 0 /* 10/100 or 1M HOME PHY */ +#define PHY_TYPE_GIG 1 /* Gigabit PHY */ +#define PHY_TYPE_SPECIAL 4 /* Special case */ +#define PHY_TYPE_RSVD 5 /* Reserved */ +#define PHY_TYPE_NON_SUP 7 /* Non-supported PHY */ + +#define AXE_PHY_NO_MASK 0x1F +#define AXE_PHY_NO(x) ((x) & AXE_PHY_NO_MASK) + +#define AXE_PHY_NO_AX772_EPHY 0x10 /* Embedded 10/100 PHY of AX88772 */ + #define AXE_TIMEOUT 1000 #define AXE_172_BUFSZ 1536 #define AXE_178_MIN_BUFSZ 2048 @@ -236,6 +251,7 @@ int axe_link; unsigned char axe_ipgs[3]; unsigned char axe_phyaddrs[2]; + int axe_phyno; struct timeval axe_rx_notice; struct usb_task axe_tick_task; int axe_bufsz;