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

Adrian Chadd adrian at freebsd.org
Wed May 23 17:55:20 UTC 2012


Hi,

Have you looked at the MDIO bus support that I brought in from Stefan?

This almost feels like a poster child for that - you'd write an MDIO
bus driver for this particular mailbox hardware interface and modify
the driver to use that, then the MDIO bus will automatically probe
whatever PHYs exist there

That way it could be reused for other MDIO bus consumers too, such as
switch PHYs and other MDIO-but-not-quite-PHY devices.

Adrian

On 22 May 2012 19:02, Pyun YongHyeon <yongari at freebsd.org> wrote:
> 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-all mailing list