svn commit: r235818 - stable/9/sys/dev/bce

Pyun YongHyeon yongari at FreeBSD.org
Wed May 23 02:02:30 UTC 2012


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;


More information about the svn-src-stable-9 mailing list