tech-kern archive

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

brgphy(4) and bnx(4) BCM5709S (SerDes) support



Dear all,

Just FYI, in case someone else might be working on it: I am about to
update bnx(4) and brgphy(4) to support Broadcom cards with SerDes PHY
(BCM 5709S). Preliminary patch is attached.

Code originates from OpenBSD, with a few modifications here and there to
adapt to our own drivers (of interest: endianness support)

Unfortunately, I cannot test it for regressions extensively, as I don't
have any bnx(4) NIC at hand (I have only access to a Dell M710, kindly
provided by Uwe Toenjes, which contains BCM5709S NICs). So, if anyone
has a NIC working through bnx(4), and could eventually test the upcoming
patch, please mail me. bge(4) should remain unaffected.

SerDes and endianness support will be committed separately, once I get
confirmation that bnx(4) and brgphy(4) still work. Ideally, the
endianness patch should be tested on a big endian arch (sparc64)

Thanks to Uwe Toenjes <6bone.informatik.uni-leipzig.de> , who kindly
gave me access to a Dell M710 for porting and testing.

-- 
Jean-Yves Migeon
jeanyves.migeon%free.fr@localhost
Index: sys/dev/mii/brgphy.c
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/brgphy.c,v
retrieving revision 1.56
diff -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        27 Nov 2010 18:35:31 -0000
@@ -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,35 @@ 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;
+#define        ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define        PRINT(str)      aprint_normal("%s%s", sep, str); sep = ", "
+               /* forcer sur extcapabilities si ca marche pas */
+               ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
+                   sc->mii_inst), BMCR_S1000 | BMCR_FDX);
+               PRINT("1000baseSX");
+               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");
+                       }
+               }
+
+               ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
+
+               sc->mii_flags |= MIIF_IS_1000X;
+
+               sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
+#undef ADD
+#undef PRINT
+       } else
                mii_phy_add_media(sc);
        aprint_normal("\n");
 
@@ -399,14 +429,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 +453,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;
 }
@@ -519,6 +590,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 +665,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 +718,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 +781,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 -r1.4 brgphyreg.h
--- sys/dev/mii/brgphyreg.h     19 Apr 2009 11:10:36 -0000      1.4
+++ sys/dev/mii/brgphyreg.h     27 Nov 2010 18:35:31 -0000
@@ -223,6 +223,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 -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        27 Nov 2010 18:35:33 -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 -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     27 Nov 2010 18:35:35 -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