From owner-svn-src-all@FreeBSD.ORG Wed May 23 02:02:30 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 693401065688; Wed, 23 May 2012 02:02:30 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5183D8FC18; Wed, 23 May 2012 02:02:30 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q4N22UYM041841; Wed, 23 May 2012 02:02:30 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q4N22UDA041838; Wed, 23 May 2012 02:02:30 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201205230202.q4N22UDA041838@svn.freebsd.org> From: Pyun YongHyeon Date: Wed, 23 May 2012 02:02:30 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r235818 - stable/9/sys/dev/bce X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 May 2012 02:02:30 -0000 Author: yongari Date: Wed May 23 02:02:29 2012 New Revision: 235818 URL: http://svn.freebsd.org/changeset/base/235818 Log: MFC r235151: Implement basic remote PHY support. Remote PHY allows the controller to perform MDIO type accesses to a remote transceiver using message pages defined through MRBE(multirate backplane ethernet). It's used in blade systems(e.g Dell Blade m610) which are connected to pass-through blades rather than traditional switches. This change directly manipulates firmware's mailboxes to control remote PHY such that it does not use mii(4). Alternatively, as David said, it could be implemented in brgphy(4) by creating a fake PHY and let brgphy(4) do necessary mii accesses and bce(4) can implement mailbox accesses based on the type of brgphy(4)'s mii accesses. Personally, I think it would make brgphy(4) hard to maintain since it would have to access many bce(4) registers in brgphy(4). Given that there are users who are suffering from lack of remote PHY support, it would be better to get working system rather than waiting for complete/perfect implementation. Modified: stable/9/sys/dev/bce/if_bce.c stable/9/sys/dev/bce/if_bcereg.h Directory Properties: stable/9/sys/ (props changed) stable/9/sys/amd64/include/xen/ (props changed) stable/9/sys/boot/ (props changed) stable/9/sys/boot/i386/efi/ (props changed) stable/9/sys/boot/ia64/efi/ (props changed) stable/9/sys/boot/ia64/ski/ (props changed) stable/9/sys/boot/powerpc/boot1.chrp/ (props changed) stable/9/sys/boot/powerpc/ofw/ (props changed) stable/9/sys/cddl/contrib/opensolaris/ (props changed) stable/9/sys/conf/ (props changed) stable/9/sys/contrib/dev/acpica/ (props changed) stable/9/sys/contrib/octeon-sdk/ (props changed) stable/9/sys/contrib/pf/ (props changed) stable/9/sys/contrib/x86emu/ (props changed) stable/9/sys/dev/ (props changed) stable/9/sys/dev/e1000/ (props changed) stable/9/sys/dev/ixgbe/ (props changed) stable/9/sys/fs/ (props changed) stable/9/sys/fs/ntfs/ (props changed) stable/9/sys/modules/ (props changed) Modified: stable/9/sys/dev/bce/if_bce.c ============================================================================== --- stable/9/sys/dev/bce/if_bce.c Wed May 23 01:49:50 2012 (r235817) +++ stable/9/sys/dev/bce/if_bce.c Wed May 23 02:02:29 2012 (r235818) @@ -364,6 +364,7 @@ static int bce_nvram_write (struct bce 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 @@ static void bce_release_resources (struc /****************************************************************************/ /* 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 void bce_watchdog (struct bce_s 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 @@ bce_print_adapter_info(struct bce_softc 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 @@ bce_attach(device_t dev) 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 @@ bce_attach(device_t dev) /* 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 @@ bce_attach(device_t dev) 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 @@ bce_attach(device_t dev) /* 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 @@ bce_detach(device_t dev) 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); @@ -1983,13 +2044,23 @@ bce_miibus_statchg(device_t dev) { struct bce_softc *sc; struct mii_data *mii; - int val; + struct ifmediareq ifmr; + int media_active, media_status, val; sc = device_get_softc(dev); DBENTER(BCE_VERBOSE_PHY); - mii = device_get_softc(sc->bce_miibus); + 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; + } val = REG_RD(sc, BCE_EMAC_MODE); val &= ~(BCE_EMAC_MODE_PORT | BCE_EMAC_MODE_HALF_DUPLEX | @@ -1997,7 +2068,7 @@ bce_miibus_statchg(device_t dev) BCE_EMAC_MODE_25G); /* Set MII or GMII interface based on the PHY speed. */ - 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, @@ -2026,7 +2097,7 @@ bce_miibus_statchg(device_t dev) } /* 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; @@ -2036,7 +2107,7 @@ bce_miibus_statchg(device_t dev) REG_WR(sc, BCE_EMAC_MODE, val); - if ((mii->mii_media_active & IFM_ETH_RXPAUSE) != 0) { + if ((IFM_OPTIONS(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); @@ -2046,7 +2117,7 @@ bce_miibus_statchg(device_t dev) BCE_CLRBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN); } - if ((mii->mii_media_active & IFM_ETH_TXPAUSE) != 0) { + if ((IFM_OPTIONS(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); @@ -3130,7 +3201,8 @@ bce_get_media_exit: 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 @@ -5018,6 +5090,8 @@ bce_reset(struct bce_softc *sc, u32 rese 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); @@ -6081,6 +6155,55 @@ bce_free_pg_chain(struct bce_softc *sc) } +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. */ /* */ @@ -6116,21 +6239,110 @@ bce_ifmedia_upd_locked(struct ifnet *ifp 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); @@ -6138,6 +6350,85 @@ bce_ifmedia_upd_locked(struct ifnet *ifp } +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. */ /* */ @@ -6158,11 +6449,15 @@ bce_ifmedia_sts(struct ifnet *ifp, struc 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); @@ -6199,14 +6494,26 @@ bce_phy_intr(struct bce_softc *sc) 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); + } else { + if (bootverbose) + if_printf(sc->bce_ifp, "link DOWN\n"); + if_link_state_change(sc->bce_ifp, + LINK_STATE_DOWN); + } + } /* * Assume link is down and allow * tick routine to update the state @@ -7495,10 +7802,14 @@ bce_ioctl(struct ifnet *ifp, u_long comm 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 */ @@ -8163,6 +8474,7 @@ bce_tick(void *xsc) struct bce_softc *sc = xsc; struct mii_data *mii; struct ifnet *ifp; + struct ifmediareq ifmr; ifp = sc->bce_ifp; @@ -8193,21 +8505,32 @@ bce_tick(void *xsc) goto bce_tick_exit; /* Link is down. Check what the PHY's doing. */ - mii = device_get_softc(sc->bce_miibus); - mii_tick(mii); - - /* Check if the link has come up. */ - if ((mii->mii_media_status & IFM_ACTIVE) && - (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)) { - DBPRINT(sc, BCE_VERBOSE_MISC, - "%s(): Link up!\n", __FUNCTION__); - sc->bce_link_up = TRUE; - if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || - IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX || - IFM_SUBTYPE(mii->mii_media_active) == IFM_2500_SX) && - (bce_verbose || bootverbose)) - BCE_PRINTF("Gigabit link up!\n"); + if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { + bzero(&ifmr, sizeof(ifmr)); + bce_ifmedia_sts_rphy(sc, &ifmr); + if ((ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + sc->bce_link_up = TRUE; + bce_miibus_statchg(sc->bce_dev); + } + } else { + mii = device_get_softc(sc->bce_miibus); + mii_tick(mii); + /* Check if the link has come up. */ + if ((mii->mii_media_status & IFM_ACTIVE) && + (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)) { + DBPRINT(sc, BCE_VERBOSE_MISC, "%s(): Link up!\n", + __FUNCTION__); + sc->bce_link_up = TRUE; + if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || + IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX || + IFM_SUBTYPE(mii->mii_media_active) == IFM_2500_SX) && + (bce_verbose || bootverbose)) + BCE_PRINTF("Gigabit link up!\n"); + } + } + if (sc->bce_link_up == TRUE) { /* Now that link is up, handle any outstanding TX traffic. */ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { DBPRINT(sc, BCE_VERBOSE_MISC, "%s(): Found " @@ -8221,6 +8544,36 @@ bce_tick_exit: 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; + 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. */ Modified: stable/9/sys/dev/bce/if_bcereg.h ============================================================================== --- stable/9/sys/dev/bce/if_bcereg.h Wed May 23 01:49:50 2012 (r235817) +++ stable/9/sys/dev/bce/if_bcereg.h Wed May 23 02:02:29 2012 (r235818) @@ -814,6 +814,23 @@ struct flash_spec { #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 @@ struct flash_spec { #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 @@ struct bce_softc #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;