Index: sys/dev/bce/if_bce.c =================================================================== --- sys/dev/bce/if_bce.c (revision 232950) +++ sys/dev/bce/if_bce.c (working copy) @@ -364,6 +364,7 @@ static void bce_get_rx_buffer_sizes(struct bce_softc *, int); static void bce_get_media (struct bce_softc *); static void bce_init_media (struct bce_softc *); +static u32 bce_get_rphy_link (struct bce_softc *); static void bce_dma_map_addr (void *, bus_dma_segment_t *, int, int); static int bce_dma_alloc (device_t); static void bce_dma_free (struct bce_softc *); @@ -372,6 +373,7 @@ /****************************************************************************/ /* BCE Firmware Synchronization and Load */ /****************************************************************************/ +static void bce_fw_cap_init (struct bce_softc *); static int bce_fw_sync (struct bce_softc *, u32); static void bce_load_rv2p_fw (struct bce_softc *, u32 *, u32, u32); static void bce_load_cpu_fw (struct bce_softc *, @@ -418,6 +420,7 @@ static int bce_ifmedia_upd (struct ifnet *); static int bce_ifmedia_upd_locked (struct ifnet *); static void bce_ifmedia_sts (struct ifnet *, struct ifmediareq *); +static void bce_ifmedia_sts_rphy (struct bce_softc *, struct ifmediareq *); static void bce_init_locked (struct bce_softc *); static void bce_init (void *); static void bce_mgmt_init_locked (struct bce_softc *sc); @@ -757,6 +760,13 @@ printf("2.5G"); i++; } + if (sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) { + if (i > 0) printf("|"); + printf("Remote PHY(%s)", + sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG ? + "FIBER" : "TP"); i++; + } + if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) { if (i > 0) printf("|"); printf("MFW); MFW (%s)\n", sc->bce_mfw_ver); @@ -1297,6 +1307,9 @@ if (val & BCE_PCICFG_MISC_STATUS_32BIT_DET) sc->bce_flags |= BCE_PCI_32BIT_FLAG; + /* Find the media type for the adapter. */ + bce_get_media(sc); + /* Reset controller and announce to bootcode that driver is present. */ if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) { BCE_PRINTF("%s(%d): Controller reset failed!\n", @@ -1344,9 +1357,6 @@ /* Update statistics once every second. */ sc->bce_stats_ticks = 1000000 & 0xffff00; - /* Find the media type for the adapter. */ - bce_get_media(sc); - /* Store data needed by PHY driver for backplane applications */ sc->bce_shared_hw_cfg = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG); sc->bce_port_hw_cfg = bce_shmem_rd(sc, BCE_PORT_HW_CFG_CONFIG); @@ -1386,6 +1396,15 @@ ifp->if_capabilities = BCE_IF_CAPABILITIES; } +#if __FreeBSD_version >= 800505 + /* + * Introducing IFCAP_LINKSTATE didn't bump __FreeBSD_version + * so it's approximate value. + */ + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) + ifp->if_capabilities |= IFCAP_LINKSTATE; +#endif + ifp->if_capenable = ifp->if_capabilities; /* @@ -1409,14 +1428,52 @@ /* Handle any special PHY initialization for SerDes PHYs. */ bce_init_media(sc); - /* MII child bus by attaching the PHY. */ - rc = mii_attach(dev, &sc->bce_miibus, ifp, bce_ifmedia_upd, - bce_ifmedia_sts, BMSR_DEFCAPMASK, sc->bce_phy_addr, - MII_OFFSET_ANY, MIIF_DOPAUSE); - if (rc != 0) { - BCE_PRINTF("%s(%d): attaching PHYs failed\n", __FILE__, - __LINE__); - goto bce_attach_fail; + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { + ifmedia_init(&sc->bce_ifmedia, IFM_IMASK, bce_ifmedia_upd, + bce_ifmedia_sts); + /* + * We can't manually override remote PHY's link and assume + * PHY port configuration(Fiber or TP) is not changed after + * device attach. This may not be correct though. + */ + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) != 0) { + if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) { + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_2500_SX, 0, NULL); + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_2500_SX | IFM_FDX, 0, NULL); + } + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_1000_SX, 0, NULL); + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_1000_SX | IFM_FDX, 0, NULL); + } else { + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_10_T, 0, NULL); + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_100_TX, 0, NULL); + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_1000_T, 0, NULL); + ifmedia_add(&sc->bce_ifmedia, + IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); + } + ifmedia_add(&sc->bce_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&sc->bce_ifmedia, IFM_ETHER | IFM_AUTO); + sc->bce_ifmedia.ifm_media = sc->bce_ifmedia.ifm_cur->ifm_media; + } else { + /* MII child bus by attaching the PHY. */ + rc = mii_attach(dev, &sc->bce_miibus, ifp, bce_ifmedia_upd, + bce_ifmedia_sts, BMSR_DEFCAPMASK, sc->bce_phy_addr, + MII_OFFSET_ANY, MIIF_DOPAUSE); + if (rc != 0) { + BCE_PRINTF("%s(%d): attaching PHYs failed\n", __FILE__, + __LINE__); + goto bce_attach_fail; + } } /* Attach to the Ethernet interface list. */ @@ -1521,8 +1578,12 @@ ether_ifdetach(ifp); /* If we have a child device on the MII bus remove it too. */ - bus_generic_detach(dev); - device_delete_child(dev, sc->bce_miibus); + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) + ifmedia_removeall(&sc->bce_ifmedia); + else { + bus_generic_detach(dev); + device_delete_child(dev, sc->bce_miibus); + } /* Release all remaining resources. */ bce_release_resources(sc); @@ -1984,18 +2045,28 @@ struct bce_softc *sc; struct ifnet *ifp; struct mii_data *mii; - int val; + struct ifmediareq ifmr; + int media_active, media_status, val; sc = device_get_softc(dev); DBENTER(BCE_VERBOSE_PHY); ifp = sc->bce_ifp; - mii = device_get_softc(sc->bce_miibus); - if (mii == NULL || ifp == NULL || - (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + if (ifp == NULL || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { + bzero(&ifmr, sizeof(ifmr)); + bce_ifmedia_sts_rphy(sc, &ifmr); + media_active = ifmr.ifm_active; + media_status = ifmr.ifm_status; + } else { + mii = device_get_softc(sc->bce_miibus); + media_active = mii->mii_media_active; + media_status = mii->mii_media_status; + } + sc->bce_link_up = FALSE; val = REG_RD(sc, BCE_EMAC_MODE); val &= ~(BCE_EMAC_MODE_PORT | BCE_EMAC_MODE_HALF_DUPLEX | @@ -2003,9 +2074,9 @@ BCE_EMAC_MODE_25G); /* Set MII or GMII interface based on the PHY speed. */ - if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + if ((media_status & (IFM_ACTIVE | IFM_AVALID)) == (IFM_ACTIVE | IFM_AVALID)) { - switch (IFM_SUBTYPE(mii->mii_media_active)) { + switch (IFM_SUBTYPE(media_active)) { case IFM_10_T: if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) { DBPRINT(sc, BCE_INFO_PHY, @@ -2042,7 +2113,7 @@ return; /* Set half or full duplex based on PHY settings. */ - if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { + if ((IFM_OPTIONS(media_active) & IFM_FDX) == 0) { DBPRINT(sc, BCE_INFO_PHY, "Setting Half-Duplex interface.\n"); val |= BCE_EMAC_MODE_HALF_DUPLEX; @@ -2052,7 +2123,7 @@ REG_WR(sc, BCE_EMAC_MODE, val); - if ((mii->mii_media_active & IFM_ETH_RXPAUSE) != 0) { + if ((media_active & IFM_ETH_RXPAUSE) != 0) { DBPRINT(sc, BCE_INFO_PHY, "%s(): Enabling RX flow control.\n", __FUNCTION__); BCE_SETBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN); @@ -2062,7 +2133,7 @@ BCE_CLRBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN); } - if ((mii->mii_media_active & IFM_ETH_TXPAUSE) != 0) { + if ((media_active & IFM_ETH_TXPAUSE) != 0) { DBPRINT(sc, BCE_INFO_PHY, "%s(): Enabling TX flow control.\n", __FUNCTION__); BCE_SETBIT(sc, BCE_EMAC_TX_MODE, BCE_EMAC_TX_MODE_FLOW_EN); @@ -3146,7 +3217,8 @@ static void bce_init_media(struct bce_softc *sc) { - if ((sc->bce_phy_flags & BCE_PHY_IEEE_CLAUSE_45_FLAG) != 0) { + if ((sc->bce_phy_flags & (BCE_PHY_IEEE_CLAUSE_45_FLAG | + BCE_PHY_REMOTE_CAP_FLAG)) == BCE_PHY_IEEE_CLAUSE_45_FLAG) { /* * Configure 5709S/5716S PHYs to use traditional IEEE * Clause 22 method. Otherwise we have no way to attach @@ -5034,6 +5106,8 @@ if (rc) BCE_PRINTF("%s(%d): Firmware did not complete " "initialization!\n", __FILE__, __LINE__); + /* Get firmware capabilities. */ + bce_fw_cap_init(sc); bce_reset_exit: DBEXIT(BCE_VERBOSE_RESET); @@ -6097,6 +6171,55 @@ } +static u32 +bce_get_rphy_link(struct bce_softc *sc) +{ + u32 advertise, link; + int fdpx; + + advertise = 0; + fdpx = 0; + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) != 0) + link = bce_shmem_rd(sc, BCE_RPHY_SERDES_LINK); + else + link = bce_shmem_rd(sc, BCE_RPHY_COPPER_LINK); + if (link & BCE_NETLINK_ANEG_ENB) + advertise |= BCE_NETLINK_ANEG_ENB; + if (link & BCE_NETLINK_SPEED_10HALF) + advertise |= BCE_NETLINK_SPEED_10HALF; + if (link & BCE_NETLINK_SPEED_10FULL) { + advertise |= BCE_NETLINK_SPEED_10FULL; + fdpx++; + } + if (link & BCE_NETLINK_SPEED_100HALF) + advertise |= BCE_NETLINK_SPEED_100HALF; + if (link & BCE_NETLINK_SPEED_100FULL) { + advertise |= BCE_NETLINK_SPEED_100FULL; + fdpx++; + } + if (link & BCE_NETLINK_SPEED_1000HALF) + advertise |= BCE_NETLINK_SPEED_1000HALF; + if (link & BCE_NETLINK_SPEED_1000FULL) { + advertise |= BCE_NETLINK_SPEED_1000FULL; + fdpx++; + } + if (link & BCE_NETLINK_SPEED_2500HALF) + advertise |= BCE_NETLINK_SPEED_2500HALF; + if (link & BCE_NETLINK_SPEED_2500FULL) { + advertise |= BCE_NETLINK_SPEED_2500FULL; + fdpx++; + } + if (fdpx) + advertise |= BCE_NETLINK_FC_PAUSE_SYM | + BCE_NETLINK_FC_PAUSE_ASYM; + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) + advertise |= BCE_NETLINK_PHY_APP_REMOTE | + BCE_NETLINK_ETH_AT_WIRESPEED; + + return (advertise); +} + + /****************************************************************************/ /* Set media options. */ /* */ @@ -6132,21 +6255,110 @@ struct bce_softc *sc = ifp->if_softc; struct mii_data *mii; struct mii_softc *miisc; - int error; + struct ifmedia *ifm; + u32 link; + int error, fdx; DBENTER(BCE_VERBOSE_PHY); error = 0; BCE_LOCK_ASSERT(sc); - mii = device_get_softc(sc->bce_miibus); + sc->bce_link_up = FALSE; + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { + ifm = &sc->bce_ifmedia; + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + link = 0; + fdx = IFM_OPTIONS(ifm->ifm_media) & IFM_FDX; + switch(IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + /* + * Check advertised link of remote PHY by reading + * BCE_RPHY_SERDES_LINK or BCE_RPHY_COPPER_LINK. + * Always use the same link type of remote PHY. + */ + link = bce_get_rphy_link(sc); + break; + case IFM_2500_SX: + if ((sc->bce_phy_flags & + (BCE_PHY_REMOTE_PORT_FIBER_FLAG | + BCE_PHY_2_5G_CAPABLE_FLAG)) == 0) + return (EINVAL); + /* + * XXX + * Have to enable forced 2.5Gbps configuration. + */ + if (fdx != 0) + link |= BCE_NETLINK_SPEED_2500FULL; + else + link |= BCE_NETLINK_SPEED_2500HALF; + break; + case IFM_1000_SX: + if ((sc->bce_phy_flags & + BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) + return (EINVAL); + /* + * XXX + * Have to disable 2.5Gbps configuration. + */ + if (fdx != 0) + link = BCE_NETLINK_SPEED_1000FULL; + else + link = BCE_NETLINK_SPEED_1000HALF; + break; + case IFM_1000_T: + if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) + return (EINVAL); + if (fdx != 0) + link = BCE_NETLINK_SPEED_1000FULL; + else + link = BCE_NETLINK_SPEED_1000HALF; + break; + case IFM_100_TX: + if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) + return (EINVAL); + if (fdx != 0) + link = BCE_NETLINK_SPEED_100FULL; + else + link = BCE_NETLINK_SPEED_100HALF; + break; + case IFM_10_T: + if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) + return (EINVAL); + if (fdx != 0) + link = BCE_NETLINK_SPEED_10FULL; + else + link = BCE_NETLINK_SPEED_10HALF; + break; + default: + return (EINVAL); + } + if (IFM_SUBTYPE(ifm->ifm_media) != IFM_AUTO) { + /* + * XXX + * Advertise pause capability for full-duplex media. + */ + if (fdx != 0) + link |= BCE_NETLINK_FC_PAUSE_SYM | + BCE_NETLINK_FC_PAUSE_ASYM; + if ((sc->bce_phy_flags & + BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) + link |= BCE_NETLINK_PHY_APP_REMOTE | + BCE_NETLINK_ETH_AT_WIRESPEED; + } - /* Make sure the MII bus has been enumerated. */ - if (mii) { - sc->bce_link_up = FALSE; - LIST_FOREACH(miisc, &mii->mii_phys, mii_list) - PHY_RESET(miisc); - error = mii_mediachg(mii); + bce_shmem_wr(sc, BCE_MB_ARGS_0, link); + error = bce_fw_sync(sc, BCE_DRV_MSG_CODE_CMD_SET_LINK); + } else { + mii = device_get_softc(sc->bce_miibus); + + /* Make sure the MII bus has been enumerated. */ + if (mii) { + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) + PHY_RESET(miisc); + error = mii_mediachg(mii); + } } DBEXIT(BCE_VERBOSE_PHY); @@ -6154,6 +6366,85 @@ } +static void +bce_ifmedia_sts_rphy(struct bce_softc *sc, struct ifmediareq *ifmr) +{ + struct ifnet *ifp; + u32 link; + + ifp = sc->bce_ifp; + BCE_LOCK_ASSERT(sc); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + link = bce_shmem_rd(sc, BCE_LINK_STATUS); + /* XXX handle heart beat status? */ + if ((link & BCE_LINK_STATUS_LINK_UP) != 0) + ifmr->ifm_status |= IFM_ACTIVE; + else { + ifmr->ifm_active |= IFM_NONE; + ifp->if_baudrate = 0; + return; + } + switch (link & BCE_LINK_STATUS_SPEED_MASK) { + case BCE_LINK_STATUS_10HALF: + ifmr->ifm_active |= IFM_10_T | IFM_HDX; + ifp->if_baudrate = IF_Mbps(10UL); + break; + case BCE_LINK_STATUS_10FULL: + ifmr->ifm_active |= IFM_10_T | IFM_FDX; + ifp->if_baudrate = IF_Mbps(10UL); + break; + case BCE_LINK_STATUS_100HALF: + ifmr->ifm_active |= IFM_100_TX | IFM_HDX; + ifp->if_baudrate = IF_Mbps(100UL); + break; + case BCE_LINK_STATUS_100FULL: + ifmr->ifm_active |= IFM_100_TX | IFM_FDX; + ifp->if_baudrate = IF_Mbps(100UL); + break; + case BCE_LINK_STATUS_1000HALF: + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) + ifmr->ifm_active |= IFM_1000_T | IFM_HDX; + else + ifmr->ifm_active |= IFM_1000_SX | IFM_HDX; + ifp->if_baudrate = IF_Mbps(1000UL); + break; + case BCE_LINK_STATUS_1000FULL: + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) + ifmr->ifm_active |= IFM_1000_T | IFM_FDX; + else + ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; + ifp->if_baudrate = IF_Mbps(1000UL); + break; + case BCE_LINK_STATUS_2500HALF: + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) { + ifmr->ifm_active |= IFM_NONE; + return; + } else + ifmr->ifm_active |= IFM_2500_SX | IFM_HDX; + ifp->if_baudrate = IF_Mbps(2500UL); + break; + case BCE_LINK_STATUS_2500FULL: + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) { + ifmr->ifm_active |= IFM_NONE; + return; + } else + ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; + ifp->if_baudrate = IF_Mbps(2500UL); + break; + default: + ifmr->ifm_active |= IFM_NONE; + return; + } + + if ((link & BCE_LINK_STATUS_RX_FC_ENABLED) != 0) + ifmr->ifm_active |= IFM_ETH_RXPAUSE; + if ((link & BCE_LINK_STATUS_TX_FC_ENABLED) != 0) + ifmr->ifm_active |= IFM_ETH_TXPAUSE; +} + + /****************************************************************************/ /* Reports current media status. */ /* */ @@ -6174,11 +6465,15 @@ BCE_UNLOCK(sc); return; } - mii = device_get_softc(sc->bce_miibus); - mii_pollstat(mii); - ifmr->ifm_active = mii->mii_media_active; - ifmr->ifm_status = mii->mii_media_status; + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) + bce_ifmedia_sts_rphy(sc, ifmr); + else { + mii = device_get_softc(sc->bce_miibus); + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; + } BCE_UNLOCK(sc); @@ -6215,13 +6510,27 @@ STATUS_ATTN_BITS_LINK_STATE); DBPRINT(sc, BCE_INFO_PHY, "%s(): Link is now UP.\n", __FUNCTION__); - } - else { + } else { REG_WR(sc, BCE_PCICFG_STATUS_BIT_CLEAR_CMD, STATUS_ATTN_BITS_LINK_STATE); DBPRINT(sc, BCE_INFO_PHY, "%s(): Link is now DOWN.\n", __FUNCTION__); } + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { + if (new_link_state) { + if (bootverbose) + if_printf(sc->bce_ifp, "link UP\n"); + if_link_state_change(sc->bce_ifp, + LINK_STATE_UP); + sc->bce_link_up = TRUE; + } else { + if (bootverbose) + if_printf(sc->bce_ifp, "link DOWN\n"); + if_link_state_change(sc->bce_ifp, + LINK_STATE_DOWN); + sc->bce_link_up = FALSE; + } + } /* * Link state changed, allow tick routine to update * the state baased on actual media state. @@ -6914,7 +7223,10 @@ ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - sc->bce_link_tick = TRUE; + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) + sc->bce_link_tick = FALSE; + else + sc->bce_link_tick = TRUE; bce_ifmedia_upd_locked(ifp); callout_reset(&sc->bce_tick_callout, hz, bce_tick, sc); @@ -7518,10 +7830,14 @@ case SIOCGIFMEDIA: DBPRINT(sc, BCE_VERBOSE_MISC, "Received SIOCSIFMEDIA/SIOCGIFMEDIA\n"); - - mii = device_get_softc(sc->bce_miibus); - error = ifmedia_ioctl(ifp, ifr, - &mii->mii_media, command); + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) + error = ifmedia_ioctl(ifp, ifr, &sc->bce_ifmedia, + command); + else { + mii = device_get_softc(sc->bce_miibus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, + command); + } break; /* Set interface capability */ @@ -8211,13 +8527,19 @@ /* Check that chip hasn't hung. */ bce_watchdog(sc); - /* If link is up already up then we're done. */ - if (sc->bce_link_tick == FALSE && sc->bce_link_up == TRUE) - goto bce_tick_exit; + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { + /* If link is up, reprogram EMAC. */ + if (sc->bce_link_tick == TRUE && sc->bce_link_up == TRUE) + bce_miibus_statchg(sc->bce_dev); + } else { + /* If link is already up then we're done. */ + if (sc->bce_link_tick == FALSE && sc->bce_link_up == TRUE) + goto bce_tick_exit; - /* Link is down. Check what the PHY's doing. */ - mii = device_get_softc(sc->bce_miibus); - mii_tick(mii); + /* Link is down. Check what the PHY's doing. */ + mii = device_get_softc(sc->bce_miibus); + mii_tick(mii); + } sc->bce_link_tick = FALSE; /* Now that link is up, handle any outstanding TX traffic. */ @@ -8232,6 +8554,40 @@ return; } +static void +bce_fw_cap_init(struct bce_softc *sc) +{ + u32 ack, cap, link; + + ack = 0; + cap = bce_shmem_rd(sc, BCE_FW_CAP_MB); + if ((cap & BCE_FW_CAP_SIGNATURE_MAGIC_MASK) != + BCE_FW_CAP_SIGNATURE_MAGIC) + return; + if ((cap & (BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN)) == + (BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN)) + ack |= BCE_DRV_ACK_CAP_SIGNATURE_MAGIC | + BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN; + if ((sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) != 0 && + (cap & BCE_FW_CAP_REMOTE_PHY_CAP) != 0) { + sc->bce_phy_flags &= ~BCE_PHY_REMOTE_PORT_FIBER_FLAG; + sc->bce_phy_flags |= BCE_PHY_REMOTE_CAP_FLAG; + link = bce_shmem_rd(sc, BCE_LINK_STATUS); + if ((link & BCE_LINK_STATUS_SERDES_LINK) != 0) + sc->bce_phy_flags |= BCE_PHY_REMOTE_PORT_FIBER_FLAG; + if (bce_verbose || bootverbose) + device_printf(sc->bce_dev, "Remote PHY : %s\n", + (link & BCE_LINK_STATUS_SERDES_LINK) ? + "FIBER" : "TP"); + ack |= BCE_DRV_ACK_CAP_SIGNATURE_MAGIC | + BCE_FW_CAP_REMOTE_PHY_CAP; + } + + if (ack != 0) + bce_shmem_wr(sc, BCE_DRV_ACK_CAP_MB, ack); +} + + #ifdef BCE_DEBUG /****************************************************************************/ /* Allows the driver state to be dumped through the sysctl interface. */ Index: sys/dev/bce/if_bcereg.h =================================================================== --- sys/dev/bce/if_bcereg.h (revision 232950) +++ sys/dev/bce/if_bcereg.h (working copy) @@ -814,6 +814,23 @@ #define BCE_DRV_PULSE_SEQ_MASK 0x00007fff #define BCE_MB_ARGS_0 0x00000014 +#define BCE_NETLINK_SPEED_10HALF (1<<0) +#define BCE_NETLINK_SPEED_10FULL (1<<1) +#define BCE_NETLINK_SPEED_100HALF (1<<2) +#define BCE_NETLINK_SPEED_100FULL (1<<3) +#define BCE_NETLINK_SPEED_1000HALF (1<<4) +#define BCE_NETLINK_SPEED_1000FULL (1<<5) +#define BCE_NETLINK_SPEED_2500HALF (1<<6) +#define BCE_NETLINK_SPEED_2500FULL (1<<7) +#define BCE_NETLINK_SPEED_10GHALF (1<<8) +#define BCE_NETLINK_SPEED_10GFULL (1<<9) +#define BCE_NETLINK_ANEG_ENB (1<<10) +#define BCE_NETLINK_PHY_APP_REMOTE (1<<11) +#define BCE_NETLINK_FC_PAUSE_SYM (1<<12) +#define BCE_NETLINK_FC_PAUSE_ASYM (1<<13) +#define BCE_NETLINK_ETH_AT_WIRESPEED (1<<14) +#define BCE_NETLINK_PHY_RESET (1<<15) + #define BCE_MB_ARGS_1 0x00000018 /* Indicate to the firmware not to go into the @@ -1079,6 +1096,26 @@ #define BCE_BC_STATE_BC_DBG_CMD_LOOP_CNT_MASK 0xffff #define BCE_BC_STATE_BC_DBG_CMD_LOOP_INFINITE 0xffff +#define BCE_FW_EVT_CODE_MB 0x00000354 +#define BCE_FW_EVT_CODE_SW_TIMER_EXPIRE_EVENT 0x00000000 +#define BCE_FW_EVT_CODE_LINK_EVENT 0x00000001 + +#define BCE_DRV_ACK_CAP_MB 0x00000364 +#define BCE_DRV_ACK_CAP_SIGNATURE_MAGIC 0x35450000 + +#define BCE_FW_CAP_MB 0x00000368 +#define BCE_FW_CAP_SIGNATURE_MAGIC 0xaa550000 +#define BCE_FW_ACK_SIGNATURE_MAGIC 0x52500000 +#define BCE_FW_CAP_SIGNATURE_MAGIC_MASK 0xffff0000 +#define BCE_FW_CAP_REMOTE_PHY_CAP 0x00000001 +#define BCE_FW_CAP_REMOTE_PHY_PRESENT 0x00000002 +#define BCE_FW_CAP_MFW_KEEP_VLAN 0x00000008 +#define BCE_FW_CAP_BC_KEEP_VLAN 0x00000010 + +#define BCE_RPHY_SERDES_LINK 0x00000374 + +#define BCE_RPHY_COPPER_LINK 0x00000378 + #define HOST_VIEW_SHMEM_BASE 0x167c00 /* @@ -6454,6 +6491,8 @@ #define BCE_PHY_INT_MODE_AUTO_POLLING_FLAG 0x00000100 #define BCE_PHY_INT_MODE_LINK_READY_FLAG 0x00000200 #define BCE_PHY_IEEE_CLAUSE_45_FLAG 0x00000400 +#define BCE_PHY_REMOTE_CAP_FLAG 0x00000800 +#define BCE_PHY_REMOTE_PORT_FIBER_FLAG 0x00001000 /* Values that need to be shared with the PHY driver. */ u32 bce_shared_hw_cfg;