tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

BCM5809S support in bnx(4) and brgphy(4)



Dear lists,

I have ported various modifications from OpenBSD and FreeBSD to bnx(4)
and brgphy(4) (see attach).

The modifications in question add BCM5709S support (SerDes 1000baseSX
FDX), and endianness hardware management (avoid using htole32()).

I thank anyone in advance that could have access to a bnx(4) supported
NIC (Broadcom 5400 and 5700 families) and that could test this patch,
especially on big endian system (sparc64).

There are two points I am not sure of:

- 1 -

The BCM5709S has its own custom registers for MII capabilities. This
means that I cannot use mii_phy_add_media() to attach brpghy MII
directly, and had to implement the logic directly into brgphyattach.

I can modify the bits in mii_capabilities to match what
mii_phy_add_media() does, or leave the logic inside brgphyattach().
Dunno what's the best.

- 2 -

Regarding autonegotiation, BCM5709S seems to have its own ANAR bits too:

/* Copper */
#define ANAR_X_PAUSE_NONE       (0 << 10)
#define ANAR_X_PAUSE_SYM        (1 << 10)
#define ANAR_X_PAUSE_ASYM       (2 << 10)
#define ANAR_X_PAUSE_TOWARDS    (3 << 10)

vs

/* SerDes autoneg is different from copper */
#define BRGPHY_SERDES_ANAR_NO_PAUSE     (0x0 << 7)
#define BRGPHY_SERDES_ANAR_SYM_PAUSE    (0x1 << 7)
#define BRGPHY_SERDES_ANAR_ASYM_PAUSE   (0x2 << 7)
#define BRGPHY_SERDES_ANAR_BOTH_PAUSE   (0x3 << 7)

As I don't have access to 802.3 (especially clause 37), I don't know if
its Broadcom's specific or standardized values for 1000baseSX.



Advices, and tests, are gratefully welcomed.

Many thanks to Uwe Toenjes <6bone%6bone.informatik.uni-leipzig.de@localhost> , 
who
kindly granted me access to a Dell M710 with BCM5709S NICs so I could
test my patch.

-- 
Jean-Yves Migeon
jeanyves.migeon%free.fr@localhost
Index: share/man/man4/bnx.4
===================================================================
RCS file: /cvsroot/src/share/man/man4/bnx.4,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 bnx.4
--- share/man/man4/bnx.4        17 Dec 2006 23:53:28 -0000      1.2
+++ share/man/man4/bnx.4        30 Nov 2010 23:58:42 -0000
@@ -29,7 +29,7 @@
 .\"
 .\"  $FreeBSD: /repoman/r/ncvs/src/share/man/man4/bce.4,v 1.2 2006/04/10 
20:12:17 brueffer Exp $
 .\"
-.Dd December 17, 2006
+.Dd December 1, 2010
 .Dt BNX 4
 .Os
 .Sh NAME
@@ -42,7 +42,7 @@
 The
 .Nm
 driver supports Broadcom's NetXtreme II product family, such as the
-BCM5706 PCI-X and BCM5708 PCI Express Ethernet controllers, which
+BCM5706 PCI-X and BCM5708-BCM5709 PCI Express Ethernet controllers, which
 includes the following:
 .Pp
 .Bl -bullet -compact
@@ -51,6 +51,8 @@ Dell PowerEdge 1950 integrated BCM5708 N
 .It
 Dell PowerEdge 2950 integrated BCM5708 NIC (10/100/1000baseT)
 .It
+Dell PowerEdge M710 integrated BCM5709S NIC (1000baseSX)
+.It
 HP NC370F PCI-X Multifunction Gigabit server adapter (1000baseSX)
 .It
 HP NC370T PCI-X Multifunction Gigabit server adapter (10/100/1000baseT)
@@ -118,6 +120,18 @@ Set 1000baseTX operation over twisted pa
 Only
 .Cm full-duplex
 mode is supported.
+.It Cm 1000baseSX
+Set 1000Mbps (Gigabit Ethernet) operation.
+Both
+.Cm full-duplex
+and
+.Cm half-duplex
+modes are supported.
+.It Cm 2500baseSX
+Set 2500Mbps operation.
+Only
+.Cm full-duplex
+mode is supported.
 .El
 .Pp
 The
Index: share/man/man4/brgphy.4
===================================================================
RCS file: /cvsroot/src/share/man/man4/brgphy.4,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 brgphy.4
--- share/man/man4/brgphy.4     30 Apr 2008 13:10:53 -0000      1.2
+++ share/man/man4/brgphy.4     30 Nov 2010 23:58:42 -0000
@@ -28,7 +28,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd June 1, 2001
+.Dd December 1, 2010
 .Dt BRGPHY 4
 .Os
 .Sh NAME
@@ -39,7 +39,8 @@
 .Sh DESCRIPTION
 The
 .Nm
-driver supports the Broadcom BCM5400-family Gigabit Ethernet PHYs.
+driver supports the Broadcom BCM5400-family and BCM5700-family
+Gigabit Ethernet PHYs.
 These PHYs are found on a variety of Gigabit Ethernet interfaces.
 .Sh SEE ALSO
 .Xr ifmedia 4 ,
Index: sys/dev/mii/brgphy.c
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/brgphy.c,v
retrieving revision 1.56
diff -u -p -u -p -r1.56 brgphy.c
--- sys/dev/mii/brgphy.c        27 Nov 2010 17:42:04 -0000      1.56
+++ sys/dev/mii/brgphy.c        30 Nov 2010 23:58:49 -0000
@@ -55,7 +55,7 @@
  */
 
 /*
- * driver for the Broadcom BCM5400 Gig-E PHY.
+ * driver for the Broadcom BCM5400 and BCM5700 Gig-E PHYs.
  *
  * Programming information for this PHY was gleaned from FreeBSD
  * (they were apparently able to get a datasheet from Broadcom).
@@ -81,9 +81,7 @@ __KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1
 #include <dev/mii/brgphyreg.h>
 
 #include <dev/pci/if_bgereg.h>
-#if 0
 #include <dev/pci/if_bnxreg.h>
-#endif
 
 static int     brgphymatch(device_t, cfdata_t, void *);
 static void    brgphyattach(device_t, device_t, void *);
@@ -182,6 +180,9 @@ static const struct mii_phydesc brgphys[
        { MII_OUI_BROADCOM2,            MII_MODEL_BROADCOM2_BCM5709C,
          MII_STR_BROADCOM2_BCM5709C },
 
+       { MII_OUI_BROADCOM2,            MII_MODEL_BROADCOM2_BCM5709S,
+         MII_STR_BROADCOM2_BCM5709S },
+
        { MII_OUI_BROADCOM2,            MII_MODEL_BROADCOM2_BCM5709CAX,
          MII_STR_BROADCOM2_BCM5709CAX },
 
@@ -226,6 +227,7 @@ brgphyattach(device_t parent, device_t s
        struct mii_attach_args *ma = aux;
        struct mii_data *mii = ma->mii_data;
        const struct mii_phydesc *mpd;
+       const char *sep = "";
        prop_dictionary_t dict;
 
        mpd = mii_phy_match(ma, brgphys);
@@ -253,7 +255,41 @@ brgphyattach(device_t parent, device_t s
        if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
            (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
                aprint_error("no media present");
-       else
+       else if (sc->mii_flags & MIIF_HAVEFIBER) {
+               sc->mii_anegticks = MII_ANEGTICKS_GIGE;
+               sc->mii_flags |= MIIF_IS_1000X;
+               sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
+
+#define        ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define        PRINT(str)      aprint_normal("%s%s", sep, str); sep = ", "
+               ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
+                   sc->mii_inst), BMCR_S1000 | BMCR_FDX);
+               PRINT("1000baseSX-FDX");
+
+               if (device_is_a(parent, "bnx")) {
+                       struct bnx_softc *bnx_sc = device_private(parent);
+                       /*
+                        * 2.5Gb support is a software enabled feature on the
+                        * BCM5708S and BCM5709S controllers.
+                        */
+                       if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) {
+                               ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX,
+                                   IFM_FDX, sc->mii_inst), 0);
+                               PRINT("2500baseSX-FDX");
+                       }
+               }
+
+               ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
+               PRINT("auto");
+
+               if (!pmf_device_register(self, NULL, mii_phy_resume)) {
+                       aprint_normal("\n");
+                       aprint_error_dev(self,
+                           "couldn't establish power handler");
+               }
+#undef ADD
+#undef PRINT
+       } else
                mii_phy_add_media(sc);
        aprint_normal("\n");
 
@@ -399,14 +435,13 @@ brgphy_status(struct mii_softc *sc)
 {
        struct mii_data *mii = sc->mii_pdata;
        struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
-       int bmcr, auxsts, gtsr;
+       int bmcr, bmsr, auxsts, gtsr;
 
        mii->mii_media_status = IFM_AVALID;
        mii->mii_media_active = IFM_ETHER;
 
-       auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
-
-       if (auxsts & BRGPHY_AUXSTS_LINK)
+       bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+       if (bmsr & BMSR_LINK)
                mii->mii_media_status |= IFM_ACTIVE;
 
        bmcr = PHY_READ(sc, MII_BMCR);
@@ -424,53 +459,95 @@ brgphy_status(struct mii_softc *sc)
                 * The media status bits are only valid of autonegotiation
                 * has completed (or it's disabled).
                 */
-               if ((auxsts & BRGPHY_AUXSTS_ACOMP) == 0) {
+               if ((bmsr & BMSR_ACOMP) == 0) {
                        /* Erg, still trying, I guess... */
                        mii->mii_media_active |= IFM_NONE;
                        return;
                }
 
-               switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
-               case BRGPHY_RES_1000FD:
-                       mii->mii_media_active |= IFM_1000_T|IFM_FDX;
-                       gtsr = PHY_READ(sc, MII_100T2SR);
-                       if (gtsr & GTSR_MS_RES)
-                               mii->mii_media_active |= IFM_ETH_MASTER;
-                       break;
+               if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S) {
 
-               case BRGPHY_RES_1000HD:
-                       mii->mii_media_active |= IFM_1000_T;
-                       gtsr = PHY_READ(sc, MII_100T2SR);
-                       if (gtsr & GTSR_MS_RES)
-                               mii->mii_media_active |= IFM_ETH_MASTER;
-                       break;
+                       /* 5709S has its own general purpose status registers */
+                       
+                       PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
+                           BRGPHY_BLOCK_ADDR_GP_STATUS);
 
-               case BRGPHY_RES_100FD:
-                       mii->mii_media_active |= IFM_100_TX|IFM_FDX;
-                       break;
+                       auxsts = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS);
 
-               case BRGPHY_RES_100T4:
-                       mii->mii_media_active |= IFM_100_T4;
-                       break;
+                       PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
+                           BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
 
-               case BRGPHY_RES_100HD:
-                       mii->mii_media_active |= IFM_100_TX;
-                       break;
+                       switch (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) {
+                       case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10:
+                               mii->mii_media_active |= IFM_10_FL;
+                               break;
+                       case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100:
+                               mii->mii_media_active |= IFM_100_FX;
+                               break;
+                       case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G:
+                               mii->mii_media_active |= IFM_1000_SX;
+                               break;
+                       case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G:
+                               mii->mii_media_active |= IFM_2500_SX;
+                               break;
+                       default:
+                               mii->mii_media_active |= IFM_NONE;
+                               mii->mii_media_status = 0;
+                               break;
+                       }
 
-               case BRGPHY_RES_10FD:
-                       mii->mii_media_active |= IFM_10_T|IFM_FDX;
-                       break;
+                       if (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_FDX)
+                               mii->mii_media_active |= IFM_FDX;
+                       else
+                               mii->mii_media_active |= IFM_HDX;
 
-               case BRGPHY_RES_10HD:
-                       mii->mii_media_active |= IFM_10_T;
-                       break;
+               } else {
+                       auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
 
-               default:
-                       mii->mii_media_active |= IFM_NONE;
-                       mii->mii_media_status = 0;
+                       switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
+                       case BRGPHY_RES_1000FD:
+                               mii->mii_media_active |= IFM_1000_T|IFM_FDX;
+                               gtsr = PHY_READ(sc, MII_100T2SR);
+                               if (gtsr & GTSR_MS_RES)
+                                       mii->mii_media_active |= IFM_ETH_MASTER;
+                               break;
+
+                       case BRGPHY_RES_1000HD:
+                               mii->mii_media_active |= IFM_1000_T;
+                               gtsr = PHY_READ(sc, MII_100T2SR);
+                               if (gtsr & GTSR_MS_RES)
+                                       mii->mii_media_active |= IFM_ETH_MASTER;
+                               break;
+
+                       case BRGPHY_RES_100FD:
+                               mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+                               break;
+
+                       case BRGPHY_RES_100T4:
+                               mii->mii_media_active |= IFM_100_T4;
+                               break;
+
+                       case BRGPHY_RES_100HD:
+                               mii->mii_media_active |= IFM_100_TX;
+                               break;
+
+                       case BRGPHY_RES_10FD:
+                               mii->mii_media_active |= IFM_10_T|IFM_FDX;
+                               break;
+
+                       case BRGPHY_RES_10HD:
+                               mii->mii_media_active |= IFM_10_T;
+                               break;
+
+                       default:
+                               mii->mii_media_active |= IFM_NONE;
+                               mii->mii_media_status = 0;
+                       }
                }
+
                if (mii->mii_media_active & IFM_FDX)
                        mii->mii_media_active |= mii_phy_flowstatus(sc);
+
        } else
                mii->mii_media_active = ife->ifm_media;
 }
@@ -482,18 +559,27 @@ brgphy_mii_phy_auto(struct mii_softc *sc
 
        brgphy_loop(sc);
        PHY_RESET(sc);
+
        ktcr = GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX;
        if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)
                ktcr |= GTCR_MAN_MS|GTCR_ADV_MS;
        PHY_WRITE(sc, MII_100T2CR, ktcr);
        ktcr = PHY_READ(sc, MII_100T2CR);
        DELAY(1000);
-       anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
-       if (sc->mii_flags & MIIF_DOPAUSE)
-               anar |= ANAR_FC| ANAR_X_PAUSE_ASYM;
 
+       if (sc->mii_flags & MIIF_HAVEFIBER) {
+               anar = ANAR_X_FD | ANAR_X_HD;
+               if (sc->mii_flags & MIIF_DOPAUSE)
+                       anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE;
+       } else {
+               anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
+               if (sc->mii_flags & MIIF_DOPAUSE)
+                       anar |= ANAR_FC | ANAR_X_PAUSE_ASYM;
+       }
        PHY_WRITE(sc, MII_ANAR, anar);
        DELAY(1000);
+
+       /* Start autonegotiation */
        PHY_WRITE(sc, MII_BMCR,
            BMCR_AUTOEN | BMCR_STARTNEG);
        PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
@@ -519,6 +605,7 @@ brgphy_loop(struct mii_softc *sc)
 static void
 brgphy_reset(struct mii_softc *sc)
 {
+       struct bnx_softc *bnx_sc;
        struct brgphy_softc *bsc = device_private(sc->mii_dev);
 
        mii_phy_reset(sc);
@@ -593,11 +680,11 @@ brgphy_reset(struct mii_softc *sc)
                        }
 #endif
                }
-#if 0 /* not yet */
        /* Handle any bnx (NetXtreme II) workarounds. */
-       } else if (sc->sc_isbnx) {
-               bnx_sc = sc->mii_pdata->mii_ifp->if_softc;
+       } else if (bsc->sc_isbnx) {
+               bnx_sc = device_private(device_parent(sc->mii_dev));
 
+#if 0 /* not yet */
                if (sc->mii_mpd_model == MII_MODEL_xxBROADCOM2_BCM5708S) {
                        /* Store autoneg capabilities/results in digital block 
(Page 0) */
                        PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 
BRGPHY_5708S_DIG3_PG2);
@@ -646,6 +733,58 @@ brgphy_reset(struct mii_softc *sc)
                                        PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
                                                BRGPHY_5708S_DIG_PG0);
                        }
+               } else
+#endif
+               if (sc->mii_mpd_model ==  MII_MODEL_BROADCOM2_BCM5709S) {
+                       /* Select the SerDes Digital block of the AN MMD. */
+                       PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
+                           BRGPHY_BLOCK_ADDR_SERDES_DIG);
+
+                       PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1,
+                           (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) &
+                           ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) |
+                           BRGPHY_SD_DIG_1000X_CTL1_FIBER);
+
+                       if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) {
+                               /* Select the Over 1G block of the AN MMD. */
+                               PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
+                                   BRGPHY_BLOCK_ADDR_OVER_1G);
+
+                               /*
+                                * Enable autoneg "Next Page" to advertise
+                                * 2.5G support.
+                                */
+                               PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1,
+                                   PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) |
+                                   BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
+                       }
+
+                        /*
+                         * Select the Multi-Rate Backplane Ethernet block of
+                         * the AN MMD.
+                         */
+                        PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
+                            BRGPHY_BLOCK_ADDR_MRBE);
+
+                        /* Enable MRBE speed autoneg. */
+                        PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP,
+                            PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) |
+                            BRGPHY_MRBE_MSG_PG5_NP_MBRE |
+                            BRGPHY_MRBE_MSG_PG5_NP_T2);
+
+                        /* Select the Clause 73 User B0 block of the AN MMD. */
+                        PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
+                            BRGPHY_BLOCK_ADDR_CL73_USER_B0);
+
+                        /* Enable MRBE speed autoneg. */
+                        PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1,
+                            BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP |
+                            BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR |
+                            BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG);
+
+                        PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
+                            BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
+
                } else {
                        if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
                                brgphy_ber_bug(sc);
@@ -657,7 +796,6 @@ brgphy_reset(struct mii_softc *sc)
                                brgphy_eth_wirespeed(sc);
                        }
                }
-#endif
        }
 }
 
Index: sys/dev/mii/brgphyreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/brgphyreg.h,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 brgphyreg.h
--- sys/dev/mii/brgphyreg.h     19 Apr 2009 11:10:36 -0000      1.4
+++ sys/dev/mii/brgphyreg.h     30 Nov 2010 23:58:50 -0000
@@ -197,6 +197,25 @@
 #define BRGPHY_IMR_CRCERR      0x0001  /* CEC error */
 
 /*******************************************************/
+/* Begin: Shared SerDes PHY register definitions       */
+/*******************************************************/
+
+/* SerDes autoneg is different from copper */
+#define BRGPHY_SERDES_ANAR_NO_PAUSE    (0x0 << 7)
+#define BRGPHY_SERDES_ANAR_SYM_PAUSE   (0x1 << 7)
+#define BRGPHY_SERDES_ANAR_ASYM_PAUSE  (0x2 << 7)
+#define BRGPHY_SERDES_ANAR_BOTH_PAUSE  (0x3 << 7)
+
+#define BRGPHY_SERDES_ANLPAR_NO_PAUSE  (0x0 << 7)
+#define BRGPHY_SERDES_ANLPAR_SYM_PAUSE (0x1 << 7)
+#define BRGPHY_SERDES_ANLPAR_ASYM_PAUSE        (0x2 << 7)
+#define BRGPHY_SERDES_ANLPAR_BOTH_PAUSE        (0x3 << 7)
+
+/*******************************************************/
+/* End: Shared SerDes PHY register definitions         */
+/*******************************************************/
+
+/*******************************************************/
 /* Begin: PHY register values for the 5706 PHY         */
 /*******************************************************/
 
@@ -223,6 +242,111 @@
 /* End: PHY register values for the 5706 PHY           */
 /*******************************************************/
 
+/*******************************************************/
+/* Begin: PHY register values for the 5708S SerDes PHY */
+/*******************************************************/
+
+#define BRGPHY_5708S_BMCR_2500                 0x20
+
+/* Autoneg Next Page Transmit 1 Regiser */
+#define BRGPHY_5708S_ANEG_NXT_PG_XMIT1         0x0B
+#define BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G     0x0001
+
+/* Use the BLOCK_ADDR register to select the page for registers 0x10 to 0x1E */
+#define BRGPHY_5708S_BLOCK_ADDR                        0x1f
+#define BRGPHY_5708S_DIG_PG0                   0x0000
+#define BRGPHY_5708S_DIG3_PG2                  0x0002
+#define BRGPHY_5708S_TX_MISC_PG5               0x0005
+
+/* 5708S SerDes "Digital" Registers (page 0) */
+#define BRGPHY_5708S_PG0_1000X_CTL1            0x10
+#define BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE 0x0001
+#define BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN 0x0010
+
+#define BRGPHY_5708S_PG0_1000X_STAT1           0x14
+#define BRGPHY_5708S_PG0_1000X_STAT1_SGMII     0x0001
+#define BRGPHY_5708S_PG0_1000X_STAT1_LINK      0x0002
+#define BRGPHY_5708S_PG0_1000X_STAT1_FDX       0x0004
+#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK        0x0018
+#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10  (0x0 << 3)
+#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100 (0x1 << 3)
+#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G  (0x2 << 3)
+#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G (0x3 << 3)
+
+#define BRGPHY_5708S_PG0_1000X_CTL2            0x11
+#define BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN 0x0001
+
+/* 5708S SerDes "Digital 3" Registers (page 2) */
+#define BRGPHY_5708S_PG2_DIGCTL_3_0            0x10
+#define BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE   0x0001
+
+/* 5708S SerDes "TX Misc" Registers (page 5) */
+#define BRGPHY_5708S_PG5_2500STATUS1           0x10
+
+#define BRGPHY_5708S_PG5_TXACTL1               0x15
+#define BRGPHY_5708S_PG5_TXACTL1_VCM           0x30
+
+#define BRGPHY_5708S_PG5_TXACTL3               0x17
+
+/*******************************************************/
+/* End: PHY register values for the 5708S SerDes PHY   */
+/*******************************************************/
+
+/*******************************************************/
+/* Begin: PHY register values for the 5709S SerDes PHY */
+/*******************************************************/
+
+/* 5709S SerDes "General Purpose Status" Registers */
+#define BRGPHY_BLOCK_ADDR_GP_STATUS            0x8120
+#define BRGPHY_GP_STATUS_TOP_ANEG_STATUS       0x1B
+#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK   0x3F00
+#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10     0x0000
+#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100    0x0100
+#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G     0x0200
+#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G    0x0300
+#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1GKX   0x0D00
+#define BRGPHY_GP_STATUS_TOP_ANEG_FDX          0x0008
+#define BRGPHY_GP_STATUS_TOP_ANEG_LINK_UP      0x0004
+#define BRGPHY_GP_STATUS_TOP_ANEG_CL73_COMP    0x0001
+
+/* 5709S SerDes "SerDes Digital" Registers */
+#define BRGPHY_BLOCK_ADDR_SERDES_DIG           0x8300
+#define BRGPHY_SERDES_DIG_1000X_CTL1           0x0010
+#define BRGPHY_SD_DIG_1000X_CTL1_AUTODET       0x0010
+#define BRGPHY_SD_DIG_1000X_CTL1_FIBER         0x0001
+
+/* 5709S SerDes "Over 1G" Registers */
+#define BRGPHY_BLOCK_ADDR_OVER_1G              0x8320
+#define BRGPHY_OVER_1G_UNFORMAT_PG1            0x19
+
+/* 5709S SerDes "Multi-Rate Backplane Ethernet" Registers */
+#define BRGPHY_BLOCK_ADDR_MRBE                 0x8350
+#define BRGPHY_MRBE_MSG_PG5_NP                 0x10
+#define BRGPHY_MRBE_MSG_PG5_NP_MBRE            0x0001
+#define BRGPHY_MRBE_MSG_PG5_NP_T2              0x0001
+
+/* 5709S SerDes "IEEE Clause 73 User B0" Registers */
+#define BRGPHY_BLOCK_ADDR_CL73_USER_B0         0x8370
+#define BRGPHY_CL73_USER_B0_MBRE_CTL1          0x12
+#define BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP        0x2000
+#define BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR  0x4000
+#define BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG     0x8000
+
+/* 5709S SerDes "IEEE Clause 73 User B0" Registers */
+#define BRGPHY_BLOCK_ADDR_ADDR_EXT             0xFFD0
+
+/* 5709S SerDes "Combo IEEE 0" Registers */
+#define BRGPHY_BLOCK_ADDR_COMBO_IEEE0          0xFFE0
+
+#define BRGPHY_ADDR_EXT                                0x1E
+#define BRGPHY_BLOCK_ADDR                      0x1F
+
+#define BRGPHY_ADDR_EXT_AN_MMD                 0x3800
+
+/*******************************************************/
+/* End: PHY register values for the 5709S SerDes PHY   */
+/*******************************************************/
+
 #define BRGPHY_INTRS   \
        ~(BRGPHY_IMR_LNK_CHG|BRGPHY_IMR_LSP_CHG|BRGPHY_IMR_DUP_CHG)
 
Index: sys/dev/pci/if_bnx.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_bnx.c,v
retrieving revision 1.35
diff -u -p -u -p -r1.35 if_bnx.c
--- sys/dev/pci/if_bnx.c        27 Nov 2010 17:48:58 -0000      1.35
+++ sys/dev/pci/if_bnx.c        30 Nov 2010 23:58:52 -0000
@@ -44,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_bnx.c,v 1
  *   BCM5708C B1, B2
  *   BCM5708S B1, B2
  *   BCM5709C A1, C0
+ *   BCM5709S A1, C0
  *   BCM5716  C0
  *
  * The following controllers are not supported by this driver:
@@ -53,7 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_bnx.c,v 1
  *   BCM5708C A0, B0
  *   BCM5708S A0, B0
  *   BCM5709C A0  B0, B1, B2 (pre-production)
- *   BCM5709S A0, A1, B0, B1, B2, C0 (pre-production)
+ *   BCM5709S A0, B0, B1, B2 (pre-production)
  */
 
 #include <sys/callout.h>
@@ -343,6 +344,7 @@ int bnx_nvram_write(struct bnx_softc *, 
 /*                                                                          */
 /****************************************************************************/
 void   bnx_get_media(struct bnx_softc *);
+void   bnx_init_media(struct bnx_softc *);
 int    bnx_dma_alloc(struct bnx_softc *);
 void   bnx_dma_free(struct bnx_softc *);
 void   bnx_release_resources(struct bnx_softc *);
@@ -705,6 +707,9 @@ bnx_attach(device_t parent, device_t sel
        sc->bnx_mii.mii_writereg = bnx_miibus_write_reg;
        sc->bnx_mii.mii_statchg = bnx_miibus_statchg;
 
+       /* Handle any special PHY initialization for SerDes PHYs. */
+       bnx_init_media(sc);
+
        sc->bnx_ec.ec_mii = &sc->bnx_mii;
        ifmedia_init(&sc->bnx_mii.mii_media, 0, ether_mediachange,
            ether_mediastatus);
@@ -917,6 +922,16 @@ bnx_miibus_read_reg(device_t dev, int ph
                return(0);
        }
 
+       /*
+        * The BCM5709S PHY is an IEEE Clause 45 PHY
+        * with special mappings to work with IEEE
+        * Clause 22 register accesses.
+        */
+       if ((sc->bnx_phy_flags & BNX_PHY_IEEE_CLAUSE_45_FLAG) != 0) {
+               if (reg >= MII_BMCR && reg <= MII_ANLPRNP)
+                       reg += 0x10;
+       }
+
        if (sc->bnx_phy_flags & BNX_PHY_INT_MODE_AUTO_POLLING_FLAG) {
                val = REG_RD(sc, BNX_EMAC_MDIO_MODE);
                val &= ~BNX_EMAC_MDIO_MODE_AUTO_POLL;
@@ -996,6 +1011,16 @@ bnx_miibus_write_reg(device_t dev, int p
            "val = 0x%04X\n", __func__,
            phy, (u_int16_t) reg & 0xffff, (u_int16_t) val & 0xffff);
 
+       /*
+        * The BCM5709S PHY is an IEEE Clause 45 PHY
+        * with special mappings to work with IEEE
+        * Clause 22 register accesses.
+        */
+       if ((sc->bnx_phy_flags & BNX_PHY_IEEE_CLAUSE_45_FLAG) != 0) {
+               if (reg >= MII_BMCR && reg <= MII_ANLPRNP)
+                       reg += 0x10;
+       }
+
        if (sc->bnx_phy_flags & BNX_PHY_INT_MODE_AUTO_POLLING_FLAG) {
                val1 = REG_RD(sc, BNX_EMAC_MDIO_MODE);
                val1 &= ~BNX_EMAC_MDIO_MODE_AUTO_POLL;
@@ -2002,6 +2027,14 @@ bnx_get_media(struct bnx_softc *sc)
                u_int32_t val;
  
                sc->bnx_flags |= BNX_NO_WOL_FLAG;
+
+               if (BNX_CHIP_NUM(sc) == BNX_CHIP_NUM_5709)
+                       sc->bnx_phy_flags |= BNX_PHY_IEEE_CLAUSE_45_FLAG;
+
+               /*
+                * The BCM5708S, BCM5709S, and BCM5716S controllers use a
+                * separate PHY for SerDes.
+                */
                if (BNX_CHIP_NUM(sc) != BNX_CHIP_NUM_5706) {
                        sc->bnx_phy_addr = 2;
                        val = REG_RD_IND(sc, sc->bnx_shmem_base +
@@ -2022,6 +2055,36 @@ bnx_get_media_exit:
 }
 
 /****************************************************************************/
+/* Performs PHY initialization required before MII drivers access the       */
+/* device.                                                                  */
+/*                                                                          */
+/* Returns:                                                                 */
+/*   Nothing.                                                               */
+/****************************************************************************/
+void
+bnx_init_media(struct bnx_softc *sc)
+{
+       if (sc->bnx_phy_flags & BNX_PHY_IEEE_CLAUSE_45_FLAG) {
+               /*
+                * Configure the BCM5709S / BCM5716S PHYs to use traditional
+                * IEEE Clause 22 method. Otherwise we have no way to attach
+                * the PHY to the mii(4) layer. PHY specific configuration
+                * is done by the mii(4) layer.
+                */
+
+               /* Select auto-negotiation MMD of the PHY. */
+               bnx_miibus_write_reg(sc->bnx_dev, sc->bnx_phy_addr,
+                   BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_ADDR_EXT);
+
+               bnx_miibus_write_reg(sc->bnx_dev, sc->bnx_phy_addr,
+                   BRGPHY_ADDR_EXT, BRGPHY_ADDR_EXT_AN_MMD);
+
+               bnx_miibus_write_reg(sc->bnx_dev, sc->bnx_phy_addr,
+                   BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
+       }
+}
+
+/****************************************************************************/
 /* Free any DMA memory owned by the driver.                                 */
 /*                                                                          */
 /* Scans through each data structre that requires DMA memory and frees      */
@@ -3607,12 +3670,12 @@ bnx_add_buf(struct bnx_softc *sc, struct
         */
        rxbd = &sc->rx_bd_chain[RX_PAGE(*chain_prod)][RX_IDX(*chain_prod)];
 
-       addr = (u_int32_t)(map->dm_segs[0].ds_addr);
-       rxbd->rx_bd_haddr_lo = htole32(addr);
+       addr = (u_int32_t)map->dm_segs[0].ds_addr;
+       rxbd->rx_bd_haddr_lo = addr;
        addr = (u_int32_t)((u_int64_t)map->dm_segs[0].ds_addr >> 32);
-       rxbd->rx_bd_haddr_hi = htole32(addr);
-       rxbd->rx_bd_len = htole32(map->dm_segs[0].ds_len);
-       rxbd->rx_bd_flags = htole32(RX_BD_FLAGS_START);
+       rxbd->rx_bd_haddr_hi = addr;
+       rxbd->rx_bd_len = map->dm_segs[0].ds_len;
+       rxbd->rx_bd_flags = RX_BD_FLAGS_START;
        *prod_bseq += map->dm_segs[0].ds_len;
        bus_dmamap_sync(sc->bnx_dmatag,
            sc->rx_bd_chain_map[RX_PAGE(*chain_prod)],
@@ -3626,11 +3689,11 @@ bnx_add_buf(struct bnx_softc *sc, struct
                rxbd =
                    &sc->rx_bd_chain[RX_PAGE(*chain_prod)][RX_IDX(*chain_prod)];
 
-               addr = (u_int32_t)(map->dm_segs[i].ds_addr);
-               rxbd->rx_bd_haddr_lo = htole32(addr);
+               addr = (u_int32_t)map->dm_segs[i].ds_addr;
+               rxbd->rx_bd_haddr_lo = addr;
                addr = (u_int32_t)((u_int64_t)map->dm_segs[i].ds_addr >> 32);
-               rxbd->rx_bd_haddr_hi = htole32(addr);
-               rxbd->rx_bd_len = htole32(map->dm_segs[i].ds_len);
+               rxbd->rx_bd_haddr_hi = addr;
+               rxbd->rx_bd_len = map->dm_segs[i].ds_len;
                rxbd->rx_bd_flags = 0;
                *prod_bseq += map->dm_segs[i].ds_len;
                bus_dmamap_sync(sc->bnx_dmatag,
@@ -3639,7 +3702,7 @@ bnx_add_buf(struct bnx_softc *sc, struct
                    sizeof(struct rx_bd), BUS_DMASYNC_PREREAD | 
BUS_DMASYNC_PREWRITE);
        }
 
-       rxbd->rx_bd_flags |= htole32(RX_BD_FLAGS_END);
+       rxbd->rx_bd_flags |= RX_BD_FLAGS_END;
        bus_dmamap_sync(sc->bnx_dmatag,
            sc->rx_bd_chain_map[RX_PAGE(*chain_prod)],
            sizeof(struct rx_bd) * RX_IDX(*chain_prod),
@@ -3894,10 +3957,10 @@ bnx_init_tx_chain(struct bnx_softc *sc)
                else
                        j = i + 1;
 
-               addr = (u_int32_t)(sc->tx_bd_chain_paddr[j]);
-               txbd->tx_bd_haddr_lo = htole32(addr);
+               addr = (u_int32_t)sc->tx_bd_chain_paddr[j];
+               txbd->tx_bd_haddr_lo = addr;
                addr = (u_int32_t)((u_int64_t)sc->tx_bd_chain_paddr[j] >> 32);
-               txbd->tx_bd_haddr_hi = htole32(addr);
+               txbd->tx_bd_haddr_hi = addr;
                bus_dmamap_sync(sc->bnx_dmatag, sc->tx_bd_chain_map[i], 0,
                    BNX_TX_CHAIN_PAGE_SZ, BUS_DMASYNC_PREWRITE);
        }
@@ -4062,9 +4125,9 @@ bnx_init_rx_chain(struct bnx_softc *sc)
 
                /* Setup the chain page pointers. */
                addr = (u_int32_t)((u_int64_t)sc->rx_bd_chain_paddr[j] >> 32);
-               rxbd->rx_bd_haddr_hi = htole32(addr);
-               addr = (u_int32_t)(sc->rx_bd_chain_paddr[j]);
-               rxbd->rx_bd_haddr_lo = htole32(addr);
+               rxbd->rx_bd_haddr_hi = addr;
+               addr = (u_int32_t)sc->rx_bd_chain_paddr[j];
+               rxbd->rx_bd_haddr_lo = addr;
                bus_dmamap_sync(sc->bnx_dmatag, sc->rx_bd_chain_map[i],
                    0, BNX_RX_CHAIN_PAGE_SZ,
                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -4843,20 +4906,20 @@ again:
                chain_prod = TX_CHAIN_IDX(prod);
                txbd = 
&sc->tx_bd_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)];
  
-               addr = (u_int32_t)(map->dm_segs[i].ds_addr);
-               txbd->tx_bd_haddr_lo = htole32(addr);
+               addr = (u_int32_t)map->dm_segs[i].ds_addr;
+               txbd->tx_bd_haddr_lo = addr;
                addr = (u_int32_t)((u_int64_t)map->dm_segs[i].ds_addr >> 32);
-               txbd->tx_bd_haddr_hi = htole32(addr);
-               txbd->tx_bd_mss_nbytes = htole16(map->dm_segs[i].ds_len);
-               txbd->tx_bd_vlan_tag = htole16(vlan_tag);
-               txbd->tx_bd_flags = htole16(flags);
+               txbd->tx_bd_haddr_hi = addr;
+               txbd->tx_bd_mss_nbytes = map->dm_segs[i].ds_len;
+               txbd->tx_bd_vlan_tag = vlan_tag;
+               txbd->tx_bd_flags = flags;
                prod_bseq += map->dm_segs[i].ds_len;
                if (i == 0)
-                       txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_START);
+                       txbd->tx_bd_flags |= TX_BD_FLAGS_START;
                prod = NEXT_TX_BD(prod);
        }
        /* Set the END flag on the last TX buffer descriptor. */
-       txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_END);
+       txbd->tx_bd_flags |= TX_BD_FLAGS_END;
  
        DBRUN(BNX_INFO_SEND, bnx_dump_tx_chain(sc, debug_prod, map->dm_nsegs));
  
Index: sys/dev/pci/if_bnxreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_bnxreg.h,v
retrieving revision 1.10
diff -u -p -u -p -r1.10 if_bnxreg.h
--- sys/dev/pci/if_bnxreg.h     19 Jan 2010 22:07:00 -0000      1.10
+++ sys/dev/pci/if_bnxreg.h     30 Nov 2010 23:58:54 -0000
@@ -718,8 +718,13 @@ struct tx_bd {
        u_int32_t tx_bd_haddr_hi;
        u_int32_t tx_bd_haddr_lo;
        u_int32_t tx_bd_mss_nbytes;
+#if BYTE_ORDER == BIG_ENDIAN
+       u_int16_t tx_bd_vlan_tag;
+       u_int16_t tx_bd_flags;
+#else
        u_int16_t tx_bd_flags;
        u_int16_t tx_bd_vlan_tag;
+#endif
                #define TX_BD_FLAGS_CONN_FAULT          (1<<0)
                #define TX_BD_FLAGS_TCP_UDP_CKSUM       (1<<1)
                #define TX_BD_FLAGS_IP_CKSUM            (1<<2)
@@ -4588,7 +4593,6 @@ struct l2_fhdr {
 #define DMA_WRITE_CHANS        3
 
 /* Use the natural page size of the host CPU. */
-/* XXX: This has only been tested on amd64/i386 systems using 4KB pages. */
 #define BCM_PAGE_BITS  PAGE_SHIFT      
 #define BCM_PAGE_SIZE  PAGE_SIZE
 
@@ -4612,7 +4616,7 @@ struct l2_fhdr {
 
 #define TX_CHAIN_IDX(x) ((x) & MAX_TX_BD)
 
-#define TX_PAGE(x) (((x) & ~USABLE_TX_BD_PER_PAGE) >> 8)
+#define TX_PAGE(x) (((x) & ~USABLE_TX_BD_PER_PAGE) >> (BCM_PAGE_BITS - 4))
 #define TX_IDX(x) ((x) & USABLE_TX_BD_PER_PAGE)
 
 #define NEXT_RX_BD(x) (((x) & USABLE_RX_BD_PER_PAGE) ==        \
@@ -4621,7 +4625,7 @@ struct l2_fhdr {
 
 #define RX_CHAIN_IDX(x) ((x) & MAX_RX_BD)
 
-#define RX_PAGE(x) (((x) & ~USABLE_RX_BD_PER_PAGE) >> 8)
+#define RX_PAGE(x) (((x) & ~USABLE_RX_BD_PER_PAGE) >> (BCM_PAGE_BITS - 4))
 #define RX_IDX(x) ((x) & USABLE_RX_BD_PER_PAGE)
 
 /* Context size. */
@@ -4800,6 +4804,7 @@ struct bnx_softc
 #define BNX_PHY_INT_MODE_MASK_FLAG             0x300
 #define BNX_PHY_INT_MODE_AUTO_POLLING_FLAG     0x100
 #define BNX_PHY_INT_MODE_LINK_READY_FLAG       0x200
+#define BNX_PHY_IEEE_CLAUSE_45_FLAG            0x400
 
        /* Values that need to be shared with the PHY driver. */
        u_int32_t               bnx_shared_hw_cfg;


Home | Main Index | Thread Index | Old Index