summaryrefslogtreecommitdiffstats
path: root/sys/dev/bce
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2012-05-09 01:55:23 +0000
committeryongari <yongari@FreeBSD.org>2012-05-09 01:55:23 +0000
commit62a24888237bd813997b2923ac098f311a35609b (patch)
tree6758d1c830cf49f24f615fd4f30260cd1f98fbc4 /sys/dev/bce
parentcf039ecfbba42330c58deb861dd983ccbabde733 (diff)
downloadFreeBSD-src-62a24888237bd813997b2923ac098f311a35609b.zip
FreeBSD-src-62a24888237bd813997b2923ac098f311a35609b.tar.gz
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. Tested by: Jan Winter ( jan.winter <> kantarmedia dot de ) Reviewed by: davidch (initial version) MFC after: 2 weeks
Diffstat (limited to 'sys/dev/bce')
-rw-r--r--sys/dev/bce/if_bce.c457
-rw-r--r--sys/dev/bce/if_bcereg.h39
2 files changed, 444 insertions, 52 deletions
diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c
index 263c832..b7b2147 100644
--- a/sys/dev/bce/if_bce.c
+++ b/sys/dev/bce/if_bce.c
@@ -364,6 +364,7 @@ static int bce_nvram_write (struct bce_softc *, u32, u8 *, int);
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 (struct bce_softc *);
/****************************************************************************/
/* 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_softc *);
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 *sc)
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 reset_code)
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, struct ifmediareq *ifmr)
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 command, caddr_t data)
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. */
diff --git a/sys/dev/bce/if_bcereg.h b/sys/dev/bce/if_bcereg.h
index f74c4d2..be20608 100644
--- a/sys/dev/bce/if_bcereg.h
+++ b/sys/dev/bce/if_bcereg.h
@@ -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;
OpenPOWER on IntegriCloud