[Midnightbsd-cvs] src: dev/mii: merge changes

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Tue Nov 25 12:04:42 EST 2008


Log Message:
-----------
merge changes

Modified Files:
--------------
    src/sys/dev/mii:
        brgphy.c (r1.2 -> r1.3)
        mii.c (r1.2 -> r1.3)
        miidevs (r1.2 -> r1.3)

-------------- next part --------------
Index: mii.c
===================================================================
RCS file: /home/cvs/src/sys/dev/mii/mii.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/mii/mii.c -L sys/dev/mii/mii.c -u -r1.2 -r1.3
--- sys/dev/mii/mii.c
+++ sys/dev/mii/mii.c
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/dev/mii/mii.c,v 1.26.2.1 2006/03/17 20:17:43 glebius Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/mii/mii.c,v 1.29 2007/05/01 18:21:24 marcel Exp $");
 
 /*
  * MII bus layer, glues MII-capable network interface drivers to sharable
@@ -64,6 +64,7 @@
 
 #include "miibus_if.h"
 
+static int miibus_print_child(device_t dev, device_t child);
 static int miibus_child_location_str(device_t bus, device_t child, char *buf,
     size_t buflen);
 static int miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
@@ -82,7 +83,7 @@
 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
 
 	/* bus interface */
-	DEVMETHOD(bus_print_child,	bus_generic_print_child),
+	DEVMETHOD(bus_print_child,	miibus_print_child),
 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
 	DEVMETHOD(bus_child_pnpinfo_str, miibus_child_pnpinfo_str),
 	DEVMETHOD(bus_child_location_str, miibus_child_location_str),
@@ -105,6 +106,11 @@
 	sizeof(struct mii_data)
 };
 
+struct miibus_ivars {
+	ifm_change_cb_t	ifmedia_upd;
+	ifm_stat_cb_t	ifmedia_sts;
+};
+
 /*
  * Helper function used by network interface drivers, attaches PHYs
  * to the network interface driver parent.
@@ -165,9 +171,7 @@
 int
 miibus_attach(device_t dev)
 {
-	void			**v;
-	ifm_change_cb_t		ifmedia_upd;
-	ifm_stat_cb_t		ifmedia_sts;
+	struct miibus_ivars	*ivars;
 	struct mii_data		*mii;
 
 	mii = device_get_softc(dev);
@@ -176,10 +180,9 @@
 	 * XXX: EVIL HACK!
 	 */
 	mii->mii_ifp = *(struct ifnet**)device_get_softc(device_get_parent(dev));
-	v = device_get_ivars(dev);
-	ifmedia_upd = v[0];
-	ifmedia_sts = v[1];
-	ifmedia_init(&mii->mii_media, IFM_IMASK, ifmedia_upd, ifmedia_sts);
+	ivars = device_get_ivars(dev);
+	ifmedia_init(&mii->mii_media, IFM_IMASK, ivars->ifmedia_upd,
+	    ivars->ifmedia_sts);
 	bus_generic_attach(dev);
 
 	return(0);
@@ -199,6 +202,20 @@
 }
 
 static int
+miibus_print_child(device_t dev, device_t child)
+{
+	struct mii_attach_args *ma;
+	int retval;
+
+	ma = device_get_ivars(child);
+	retval = bus_print_child_header(dev, child);
+	retval += printf(" PHY %d", ma->mii_phyno);
+	retval += bus_print_child_footer(dev, child);
+
+	return (retval);
+}
+
+static int
 miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
     size_t buflen)
 {
@@ -309,17 +326,16 @@
 mii_phy_probe(device_t dev, device_t *child, ifm_change_cb_t ifmedia_upd,
     ifm_stat_cb_t ifmedia_sts)
 {
-	void			**v;
+	struct miibus_ivars	*ivars;
 	int			bmsr, i;
 
-	v = malloc(sizeof(vm_offset_t) * 2, M_DEVBUF, M_NOWAIT);
-	if (v == 0) {
+	ivars = malloc(sizeof(*ivars), M_DEVBUF, M_NOWAIT);
+	if (ivars == NULL)
 		return (ENOMEM);
-	}
-	v[0] = ifmedia_upd;
-	v[1] = ifmedia_sts;
+	ivars->ifmedia_upd = ifmedia_upd;
+	ivars->ifmedia_sts = ifmedia_sts;
 	*child = device_add_child(dev, "miibus", -1);
-	device_set_ivars(*child, v);
+	device_set_ivars(*child, ivars);
 
 	for (i = 0; i < MII_NPHY; i++) {
 		bmsr = MIIBUS_READREG(dev, i, MII_BMSR);
Index: miidevs
===================================================================
RCS file: /home/cvs/src/sys/dev/mii/miidevs,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/mii/miidevs -L sys/dev/mii/miidevs -u -r1.2 -r1.3
--- sys/dev/mii/miidevs
+++ sys/dev/mii/miidevs
@@ -1,4 +1,4 @@
-$FreeBSD: /repoman/r/ncvs/src/sys/dev/mii/miidevs,v 1.30.2.1.2.1 2006/04/12 18:09:28 ps Exp $
+$FreeBSD: src/sys/dev/mii/miidevs,v 1.46.2.1 2007/11/05 01:42:02 yongari Exp $
 /*$NetBSD: miidevs,v 1.6 1999/05/14 11:37:30 drochner Exp $*/
 
 /*-
@@ -54,6 +54,7 @@
 oui BROADCOM			0x001018	Broadcom Corporation
 oui CICADA			0x0003F1	Cicada Semiconductor
 oui DAVICOM			0x00606e	Davicom Semiconductor
+oui ICPLUS			0x0090c3	IC Plus Corp.
 oui ICS				0x00a0be	Integrated Circuit Systems
 oui INTEL			0x00aa00	Intel
 oui JATO			0x00e083	Jato Technologies
@@ -65,6 +66,7 @@
 oui SIS				0x00e006	Silicon Integrated Systems
 oui TDK				0x00c039	TDK
 oui TI				0x080028	Texas Instruments
+oui VITESSE			0x0001c1	Vitesse Semiconductor
 oui XAQTI			0x00e0ae	XaQti Corp.
 oui MARVELL			0x005043	Marvell Semiconductor
 oui xxMARVELL			0x000ac2	Marvell Semiconductor
@@ -79,6 +81,7 @@
 	(ie, ordered as on the wire) */
 oui xxALTIMA			0x000895	Altima Communications
 oui xxBROADCOM			0x000818	Broadcom Corporation
+oui xxBROADCOM_ALT1		0x0050ef	Broadcom Corporation
 oui xxICS			0x00057d	Integrated Circuit Systems
 oui xxSEEQ			0x0005be	Seeq
 oui xxSIS			0x000760	Silicon Integrated Systems
@@ -92,7 +95,7 @@
 /* Don't know what's going on here. */
 oui xxDAVICOM			0x006040	Davicom Semiconductor
 
-/* This is the OUI of the gigE PHY in the RealTek 8169S/8110S chips */
+/* This is the OUI of the gigE PHY in the RealTek 8169S/8110S/8211B chips */
 oui xxREALTEK			0x000732
 
 /*
@@ -102,11 +105,12 @@
 /* Altima Communications PHYs */
 model xxALTIMA AC101		0x0021 AC101 10/100 media interface
 model xxALTIMA AC101L		0x0012 AC101L 10/100 media interface
+model xxALTIMA ACXXX		0x0001 ACXXX 10/100 media interface
 
 /* Advanced Micro Devices PHYs */
-model xxAMD 79C873		0x0000 Am79C873 10/100 media interface
 model AMD 79c973phy		0x0036 Am79c973 internal PHY
 model AMD 79c978		0x0039 Am79c978 HomePNA PHY
+model xxAMD 79C873		0x0000 Am79C873/DM9101 10/100 media interface
 
 /* Broadcom Corp. PHYs. */
 model BROADCOM 3C905B		0x0012 3c905B 10/100 internal PHY
@@ -117,26 +121,40 @@
 model xxBROADCOM BCM5400	0x0004 Broadcom 1000baseTX PHY
 model xxBROADCOM BCM5401	0x0005 BCM5401 10/100/1000baseTX PHY
 model xxBROADCOM BCM5411	0x0007 BCM5411 10/100/1000baseTX PHY
+model xxBROADCOM BCM5754	0x000e BCM5754 10/100/1000baseTX PHY
+model xxBROADCOM BCM5752	0x0010 BCM5752 10/100/1000baseTX PHY
 model xxBROADCOM BCM5701	0x0011 BCM5701 10/100/1000baseTX PHY
+model xxBROADCOM BCM5706	0x0015 BCM5706 10/100/1000baseTX/SX PHY
 model xxBROADCOM BCM5703	0x0016 BCM5703 10/100/1000baseTX PHY
 model xxBROADCOM BCM5704	0x0019 BCM5704 10/100/1000baseTX PHY
 model xxBROADCOM BCM5705	0x001a BCM5705 10/100/1000baseTX PHY
 model xxBROADCOM BCM5750	0x0018 BCM5750 10/100/1000baseTX PHY
 model xxBROADCOM BCM5714	0x0034 BCM5714 10/100/1000baseTX PHY
 model xxBROADCOM BCM5780	0x0035 BCM5780 10/100/1000baseTX PHY
-model xxBROADCOM BCM5706C	0x0015 BCM5706C 10/100/1000baseTX PHY
 model xxBROADCOM BCM5708C	0x0036 BCM5708C 10/100/1000baseTX PHY
+model xxBROADCOM_ALT1 BCM5755	0x000c BCM5755 10/100/1000baseTX PHY
+model xxBROADCOM_ALT1 BCM5787	0x000e BCM5787 10/100/1000baseTX PHY
+model xxBROADCOM_ALT1 BCM5708S	0x0015 BCM5708S 1000/2500BaseSX PHY
 
 /* Cicada Semiconductor PHYs (now owned by Vitesse?) */
 model CICADA CS8201		0x0001 Cicada CS8201 10/100/1000TX PHY
 model CICADA CS8201A		0x0020 Cicada CS8201 10/100/1000TX PHY
 model CICADA CS8201B		0x0021 Cicada CS8201 10/100/1000TX PHY
+model VITESSE VSC8601		0x0002 Vitesse VSC8601 10/100/1000TX PHY
 
 /* Davicom Semiconductor PHYs */
+model DAVICOM DM9102		0x0004 DM9102 10/100 media interface
 model xxDAVICOM DM9101		0x0000 DM9101 10/100 media interface
 
 /* Integrated Circuit Systems PHYs */
+model xxICS 1889		0x0001 ICS1889 10/100 media interface
 model xxICS 1890		0x0002 ICS1890 10/100 media interface
+model xxICS 1892		0x0003 ICS1892 10/100 media interface
+model xxICS 1893		0x0004 ICS1893 10/100 media interface
+
+/* IC Plus Corp. PHYs */
+model ICPLUS IP101		0x0005 IC Plus 10/100 PHY
+model ICPLUS IP1000A		0x0008 IC Plus 10/100/1000 media interface
 
 /* Intel PHYs */
 model xxINTEL I82553AB		0x0000 i83553 10/100 media interface
@@ -162,7 +180,8 @@
 
 /* RealTek Semiconductor PHYs */
 model REALTEK RTL8201L		0x0020 RTL8201L 10/100 media interface
-model xxREALTEK RTL8169S	0x0011 RTL8169S/8110S media interface
+model xxREALTEK RTL8305SC	0x0005 RTL8305SC 10/100 802.1q switch
+model xxREALTEK RTL8169S	0x0011 RTL8169S/8110S/8211B media interface
 
 /* Seeq PHYs */
 model xxSEEQ 80220		0x0003 Seeq 80220 10/100 media interface
@@ -184,4 +203,18 @@
 /* Marvell Semiconductor PHYs */
 model MARVELL E1000		0x0000 Marvell 88E1000 Gigabit PHY
 model MARVELL E1011		0x0002 Marvell 88E1011 Gigabit PHY
+model MARVELL E1000_3		0x0003 Marvell 88E1000 Gigabit PHY
+model MARVELL E1000S		0x0004 Marvell 88E1000S Gigabit PHY
+model MARVELL E1000_5		0x0005 Marvell 88E1000 Gigabit PHY
+model MARVELL E1000_6		0x0006 Marvell 88E1000 Gigabit PHY
+model MARVELL E3082		0x0008 Marvell 88E3082 10/100 Fast Ethernet PHY
+model MARVELL E1112		0x0009 Marvell 88E1112 Gigabit PHY
+model MARVELL E1149		0x000b Marvell 88E1149 Gigabit PHY
+model MARVELL E1111		0x000c Marvell 88E1111 Gigabit PHY
+model MARVELL E1116		0x0021 Marvell 88E1116 Gigabit PHY
+model MARVELL E1118		0x0022 Marvell 88E1118 Gigabit PHY
 model xxMARVELL E1000		0x0005 Marvell 88E1000 Gigabit PHY
+model xxMARVELL E1011		0x0002 Marvell 88E1011 Gigabit PHY
+model xxMARVELL E1000_3		0x0003 Marvell 88E1000 Gigabit PHY
+model xxMARVELL E1000_5		0x0005 Marvell 88E1000 Gigabit PHY
+model xxMARVELL E1111		0x000c Marvell 88E1111 Gigabit PHY
Index: brgphy.c
===================================================================
RCS file: /home/cvs/src/sys/dev/mii/brgphy.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/mii/brgphy.c -L sys/dev/mii/brgphy.c -u -r1.2 -r1.3
--- sys/dev/mii/brgphy.c
+++ sys/dev/mii/brgphy.c
@@ -31,11 +31,10 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/dev/mii/brgphy.c,v 1.34.2.3.2.2 2006/04/12 18:38:59 ps Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/mii/brgphy.c,v 1.70 2007/06/08 02:34:44 davidch Exp $");
 
 /*
- * Driver for the Broadcom BCR5400 1000baseTX PHY. Speed is always
- * 1000mbps; all we need to negotiate here is full or half duplex.
+ * Driver for the Broadcom BCM54xx/57xx 1000baseTX PHY.
  */
 
 #include <sys/param.h>
@@ -45,8 +44,6 @@
 #include <sys/socket.h>
 #include <sys/bus.h>
 
-#include <machine/clock.h>
-
 #include <net/if.h>
 #include <net/ethernet.h>
 #include <net/if_media.h>
@@ -69,6 +66,17 @@
 static int brgphy_probe(device_t);
 static int brgphy_attach(device_t);
 
+struct brgphy_softc {
+	struct mii_softc mii_sc;
+	int mii_oui;
+	int mii_model;
+	int mii_rev;
+	int serdes_flags;	/* Keeps track of the serdes type used */
+#define BRGPHY_5706S	0x0001
+#define BRGPHY_5708S	0x0002
+	int bce_phy_flags;		/* PHY flags transferred from the MAC driver */
+};
+
 static device_method_t brgphy_methods[] = {
 	/* device interface */
 	DEVMETHOD(device_probe,		brgphy_probe),
@@ -83,324 +91,292 @@
 static driver_t brgphy_driver = {
 	"brgphy",
 	brgphy_methods,
-	sizeof(struct mii_softc)
+	sizeof(struct brgphy_softc)
 };
 
 DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0);
 
 static int	brgphy_service(struct mii_softc *, struct mii_data *, int);
+static void	brgphy_setmedia(struct mii_softc *, int, int);
 static void	brgphy_status(struct mii_softc *);
-static int	brgphy_mii_phy_auto(struct mii_softc *);
+static void	brgphy_mii_phy_auto(struct mii_softc *);
 static void	brgphy_reset(struct mii_softc *);
-static void	brgphy_loop(struct mii_softc *);
+static void	brgphy_enable_loopback(struct mii_softc *);
 static void	bcm5401_load_dspcode(struct mii_softc *);
 static void	bcm5411_load_dspcode(struct mii_softc *);
-static void	bcm5703_load_dspcode(struct mii_softc *);
-static void	bcm5750_load_dspcode(struct mii_softc *);
-static int	brgphy_mii_model;
+static void	brgphy_fixup_5704_a0_bug(struct mii_softc *);
+static void	brgphy_fixup_adc_bug(struct mii_softc *);
+static void	brgphy_fixup_adjust_trim(struct mii_softc *);
+static void	brgphy_fixup_ber_bug(struct mii_softc *);
+static void	brgphy_fixup_crc_bug(struct mii_softc *);
+static void	brgphy_fixup_jitter_bug(struct mii_softc *);
+static void	brgphy_ethernet_wirespeed(struct mii_softc *);
+static void	brgphy_jumbo_settings(struct mii_softc *, u_long);
+
+static const struct mii_phydesc brgphys[] = {
+	MII_PHY_DESC(xxBROADCOM, BCM5400),
+	MII_PHY_DESC(xxBROADCOM, BCM5401),
+	MII_PHY_DESC(xxBROADCOM, BCM5411),
+	MII_PHY_DESC(xxBROADCOM, BCM5701),
+	MII_PHY_DESC(xxBROADCOM, BCM5703),
+	MII_PHY_DESC(xxBROADCOM, BCM5704),
+	MII_PHY_DESC(xxBROADCOM, BCM5705),
+	MII_PHY_DESC(xxBROADCOM, BCM5706),
+	MII_PHY_DESC(xxBROADCOM, BCM5714),
+	MII_PHY_DESC(xxBROADCOM, BCM5750),
+	MII_PHY_DESC(xxBROADCOM, BCM5752),
+	MII_PHY_DESC(xxBROADCOM, BCM5754),
+	MII_PHY_DESC(xxBROADCOM, BCM5780),
+	MII_PHY_DESC(xxBROADCOM, BCM5708C),
+	MII_PHY_DESC(xxBROADCOM_ALT1, BCM5755),
+	MII_PHY_DESC(xxBROADCOM_ALT1, BCM5787),
+	MII_PHY_DESC(xxBROADCOM_ALT1, BCM5708S),
+	MII_PHY_END
+};
+
 
+/* Search for our PHY in the list of known PHYs */
 static int
-brgphy_probe(dev)
-	device_t		dev;
+brgphy_probe(device_t dev)
 {
-	struct mii_attach_args *ma;
-
-	ma = device_get_ivars(dev);
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5400) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5400);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5401) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5401);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5411) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5411);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5701) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5701);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5703) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5703);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5704) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5704);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5705) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5705);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5750) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5750);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5714) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5714);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5780) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5780);
-		return (0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5706C) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5706C);
-		return(0);
-	}
-
-	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
-	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5708C) {
-		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5708C);
-		return(0);
-	}
-
-	return(ENXIO);
+	return (mii_phy_dev_probe(dev, brgphys, BUS_PROBE_DEFAULT));
 }
 
+/* Attach the PHY to the MII bus */
 static int
-brgphy_attach(dev)
-	device_t		dev;
+brgphy_attach(device_t dev)
 {
+	struct brgphy_softc *bsc;
+	struct bge_softc *bge_sc = NULL;
+	struct bce_softc *bce_sc = NULL;
 	struct mii_softc *sc;
 	struct mii_attach_args *ma;
 	struct mii_data *mii;
-	const char *sep = "";
-	struct bge_softc *bge_sc = NULL;
-	struct bce_softc *bce_sc = NULL;
-	int fast_ether_only = FALSE;
+	struct ifnet *ifp;
+	int fast_ether;
 
-	sc = device_get_softc(dev);
+	bsc = device_get_softc(dev);
+	sc = &bsc->mii_sc;
 	ma = device_get_ivars(dev);
 	sc->mii_dev = device_get_parent(dev);
 	mii = device_get_softc(sc->mii_dev);
 	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
 
+	/* Initialize mii_softc structure */
 	sc->mii_inst = mii->mii_instance;
 	sc->mii_phy = ma->mii_phyno;
 	sc->mii_service = brgphy_service;
 	sc->mii_pdata = mii;
-
-	sc->mii_flags |= MIIF_NOISOLATE;
+	sc->mii_anegticks = MII_ANEGTICKS_GIGE;
+	sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
 	mii->mii_instance++;
 
-#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
-#define PRINT(s)	printf("%s%s", sep, s); sep = ", "
+	/* Initialize brgphy_softc structure */
+	bsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
+	bsc->mii_model = MII_MODEL(ma->mii_id2);
+	bsc->mii_rev = MII_REV(ma->mii_id2);
+	bsc->serdes_flags = 0;
+
+	fast_ether = 0;
+
+	if (bootverbose)
+		device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n",
+		    bsc->mii_oui, bsc->mii_model, bsc->mii_rev);
+
+	/* Handle any special cases based on the PHY ID */
+	switch (bsc->mii_oui) {
+	case MII_OUI_BROADCOM: 
+		break;
+	case MII_OUI_xxBROADCOM:
+		switch (bsc->mii_model) {
+			case MII_MODEL_xxBROADCOM_BCM5706:
+				/* 
+				 * The 5464 PHY used in the 5706 supports both copper
+				 * and fiber interfaces over GMII.  Need to check the
+				 * shadow registers to see which mode is actually 
+				 * in effect, and therefore whether we have 5706C or 
+				 * 5706S.
+				 */
+				PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, 
+					BRGPHY_SHADOW_1C_MODE_CTRL);
+				if (PHY_READ(sc, BRGPHY_MII_SHADOW_1C) & 
+					BRGPHY_SHADOW_1C_ENA_1000X) {
+					bsc->serdes_flags |= BRGPHY_5706S;
+					sc->mii_flags |= MIIF_HAVEFIBER;
+				}
+				break;
+		} break;
+	case MII_OUI_xxBROADCOM_ALT1:
+		switch (bsc->mii_model) {
+			case MII_MODEL_xxBROADCOM_ALT1_BCM5708S:
+				bsc->serdes_flags |= BRGPHY_5708S;
+				sc->mii_flags |= MIIF_HAVEFIBER;
+				break;
+		} break;
+	default:
+		device_printf(dev, "Unrecognized OUI for PHY!\n");
+	}
 
-	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
-	    BMCR_ISO);
-#if 0
-	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
-	    BMCR_LOOP|BMCR_S100);
-#endif
+	ifp = sc->mii_pdata->mii_ifp;
 
-	brgphy_mii_model = MII_MODEL(ma->mii_id2);
-	brgphy_reset(sc);
+	/* Find the MAC driver associated with this PHY. */
+	if (strcmp(ifp->if_dname, "bge") == 0)	{
+		bge_sc = ifp->if_softc;
+	} else if (strcmp(ifp->if_dname, "bce") == 0) {
+		bce_sc = ifp->if_softc;
+	}
+
+	/* Todo: Need to add additional controllers such as 5906 & 5787F */
+	/* The 590x chips are 10/100 only. */
+	if (bge_sc &&
+	    pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID &&
+	    (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 ||
+	    pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2)) {
+		fast_ether = 1;
+		sc->mii_anegticks = MII_ANEGTICKS;
+	}
 
+	brgphy_reset(sc);
 
 	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
-	sc->mii_capabilities &= ~BMSR_ANEG;
+	if (sc->mii_capabilities & BMSR_EXTSTAT)
+		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
 	device_printf(dev, " ");
-	mii_add_media(sc);
 
-	/* Find the driver associated with this PHY. */
-	if (strcmp(mii->mii_ifp->if_dname, "bge") == 0)	{
- 		bge_sc = mii->mii_ifp->if_softc;
-	} else if (strcmp(mii->mii_ifp->if_dname, "bce") == 0) {
-		bce_sc = mii->mii_ifp->if_softc;
-	}
+#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
 
-	/* The 590x chips are 10/100 only. */
-	if (strcmp(mii->mii_ifp->if_dname, "bge") == 0 &&
-	    pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID &&
-	    (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 ||
-	    pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2))
-		fast_ether_only = TRUE;
+	/* Create an instance of Ethernet media. */
+	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), BMCR_ISO);
 
-	if (fast_ether_only == FALSE) {
-		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
-		    sc->mii_inst), BRGPHY_BMCR_FDX);
-		PRINT(", 1000baseTX");
-		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
-		    IFM_FDX, sc->mii_inst), 0);
-		PRINT("1000baseTX-FDX");
+	/* Add the supported media types */
+	if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
+		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
+			BRGPHY_S10);
+		printf("10baseT, ");
+		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
+			BRGPHY_S10 | BRGPHY_BMCR_FDX);
+		printf("10baseT-FDX, ");
+		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
+			BRGPHY_S100);
+		printf("100baseTX, ");
+		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
+			BRGPHY_S100 | BRGPHY_BMCR_FDX);
+		printf("100baseTX-FDX, ");
+		if (fast_ether == 0) {
+			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
+				BRGPHY_S1000);
+			printf("1000baseT, ");
+			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst),
+				BRGPHY_S1000 | BRGPHY_BMCR_FDX);
+			printf("1000baseT-FDX, ");
+		}
+	} else {
+		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
+			BRGPHY_S1000 | BRGPHY_BMCR_FDX);
+		printf("1000baseSX-FDX, ");
+		/* 2.5G support is a software enabled feature on the 5708S */
+		if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) {
+			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0);
+			printf("2500baseSX-FDX, ");
+		}
 	}
 
 	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
-	PRINT("auto");
+	printf("auto\n");
 
-	printf("\n");
 #undef ADD
-#undef PRINT
-
 	MIIBUS_MEDIAINIT(sc->mii_dev);
-	return(0);
+	return (0);
 }
 
 static int
-brgphy_service(sc, mii, cmd)
-	struct mii_softc *sc;
-	struct mii_data *mii;
-	int cmd;
+brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
 {
+	struct brgphy_softc *bsc = (struct brgphy_softc *)sc;
 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
-	int reg, speed, gig;
+	int error = 0;
+	int val;
 
 	switch (cmd) {
 	case MII_POLLSTAT:
-		/*
-		 * If we're not polling our PHY instance, just return.
-		 */
+		/* If we're not polling our PHY instance, just return. */
 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
-			return (0);
+			goto brgphy_service_exit;
 		break;
-
 	case MII_MEDIACHG:
 		/*
 		 * If the media indicates a different PHY instance,
 		 * isolate ourselves.
 		 */
 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
-			reg = PHY_READ(sc, MII_BMCR);
-			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
-			return (0);
+			PHY_WRITE(sc, MII_BMCR,
+			    PHY_READ(sc, MII_BMCR) | BMCR_ISO);
+			goto brgphy_service_exit;
 		}
 
-		/*
-		 * If the interface is not up, don't do anything.
-		 */
+		/* If the interface is not up, don't do anything. */
 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
 			break;
 
+		/* Todo: Why is this here?  Is it really needed? */
 		brgphy_reset(sc);	/* XXX hardware bug work-around */
 
 		switch (IFM_SUBTYPE(ife->ifm_media)) {
 		case IFM_AUTO:
-#ifdef foo
-			/*
-			 * If we're already in auto mode, just return.
-			 */
-			if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN)
-				return (0);
-#endif
-			(void) brgphy_mii_phy_auto(sc);
+			brgphy_mii_phy_auto(sc);
 			break;
+		case IFM_2500_SX:
+		case IFM_1000_SX:
 		case IFM_1000_T:
-			speed = BRGPHY_S1000;
-			goto setit;
 		case IFM_100_TX:
-			speed = BRGPHY_S100;
-			goto setit;
 		case IFM_10_T:
-			speed = BRGPHY_S10;
-setit:
-			brgphy_loop(sc);
-			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
-				speed |= BRGPHY_BMCR_FDX;
-				gig = BRGPHY_1000CTL_AFD;
-			} else {
-				gig = BRGPHY_1000CTL_AHD;
-			}
-
-			PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0);
-			PHY_WRITE(sc, BRGPHY_MII_BMCR, speed);
-			PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE);
-
-			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) 
-				break;
-
-			PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig);
-			PHY_WRITE(sc, BRGPHY_MII_BMCR,
-			    speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG);
-
-			if (brgphy_mii_model != MII_MODEL_xxBROADCOM_BCM5701)
-				break;
-
-			/*
-			 * When settning the link manually, one side must
-			 * be the master and the other the slave. However
-			 * ifmedia doesn't give us a good way to specify
-			 * this, so we fake it by using one of the LINK
-			 * flags. If LINK0 is set, we program the PHY to
-			 * be a master, otherwise it's a slave.
-			 */
-			if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
-				PHY_WRITE(sc, BRGPHY_MII_1000CTL,
-				    gig|BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC);
-			} else {
-				PHY_WRITE(sc, BRGPHY_MII_1000CTL,
-				    gig|BRGPHY_1000CTL_MSE);
-			}
-			break;
-#ifdef foo
-		case IFM_NONE:
-			PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
+			brgphy_setmedia(sc, ife->ifm_media,
+			    mii->mii_ifp->if_flags & IFF_LINK0);
 			break;
-#endif
-		case IFM_100_T4:
 		default:
-			return (EINVAL);
+			error = EINVAL;
+			goto brgphy_service_exit;
 		}
 		break;
-
 	case MII_TICK:
-		/*
-		 * If we're not currently selected, just return.
-		 */
+		/* Bail if we're not currently selected. */
 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
-			return (0);
+			goto brgphy_service_exit;
 
-		/*
-		 * Is the interface even up?
-		 */
+		/* Bail if the interface isn't up. */
 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
-			return (0);
+			goto brgphy_service_exit;
 
-		/*
-		 * Only used for autonegotiation.
-		 */
-		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+
+		/* Bail if autoneg isn't in process. */
+		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
+			sc->mii_ticks = 0;
 			break;
+		}
 
 		/*
 		 * Check to see if we have link.  If we do, we don't
-		 * need to restart the autonegotiation process.  Read
-		 * the BMSR twice in case it's latched.
+		 * need to restart the autonegotiation process.
 		 */
-		reg = PHY_READ(sc, BRGPHY_MII_AUXSTS);
-		if (reg & BRGPHY_AUXSTS_LINK)
+		val	= PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+		if (val & BMSR_LINK) {
+			sc->mii_ticks = 0;	/* Reset autoneg timer. */
 			break;
+		}
 
-		/*
-		 * Only retry autonegotiation every 5 seconds.
-		 */
-		if (++sc->mii_ticks <= 5)
+#if 0
+		/* Todo: Is this correct? */
+		/* Announce link loss right after it happens. */
+		if (sc->mii_ticks++ == 0)
 			break;
-		
+#endif
+
+		/* Only retry autonegotiation every mii_anegticks seconds. */
+		if (sc->mii_ticks <= sc->mii_anegticks)
+			goto brgphy_service_exit;
+
+
+		/* Retry autonegotiation */
 		sc->mii_ticks = 0;
 		brgphy_mii_phy_auto(sc);
 		break;
@@ -412,126 +388,264 @@
 	/*
 	 * Callback if something changed. Note that we need to poke
 	 * the DSP on the Broadcom PHYs if the media changes.
-	 *
 	 */
-	if (sc->mii_media_active != mii->mii_media_active || 
+	if (sc->mii_media_active != mii->mii_media_active ||
 	    sc->mii_media_status != mii->mii_media_status ||
 	    cmd == MII_MEDIACHG) {
-		switch (brgphy_mii_model) {
-		case MII_MODEL_xxBROADCOM_BCM5400:
-		case MII_MODEL_xxBROADCOM_BCM5401:
-			bcm5401_load_dspcode(sc);
+		switch (bsc->mii_oui) {
+		case MII_OUI_BROADCOM:
 			break;
-		case MII_MODEL_xxBROADCOM_BCM5411:
-			bcm5411_load_dspcode(sc);
+		case MII_OUI_xxBROADCOM:
+			switch (bsc->mii_model) {
+			case MII_MODEL_xxBROADCOM_BCM5400:
+				bcm5401_load_dspcode(sc);
+				break;
+			case MII_MODEL_xxBROADCOM_BCM5401:
+				if (bsc->mii_rev == 1 || bsc->mii_rev == 3)
+					bcm5401_load_dspcode(sc);
+				break;
+			case MII_MODEL_xxBROADCOM_BCM5411:
+				bcm5411_load_dspcode(sc);
+				break;
+			}
+			break;
+		case MII_OUI_xxBROADCOM_ALT1:
 			break;
 		}
 	}
 	mii_phy_update(sc, cmd);
-	return (0);
+brgphy_service_exit:
+	return (error);
 }
 
 static void
-brgphy_status(sc)
-	struct mii_softc *sc;
+brgphy_setmedia(struct mii_softc *sc, int media, int master)
+{
+	struct brgphy_softc *bsc = (struct brgphy_softc *)sc;
+	int bmcr = 0, gig;
+
+	switch (IFM_SUBTYPE(media)) {
+	case IFM_2500_SX:
+		break;
+	case IFM_1000_SX:
+	case IFM_1000_T:
+		bmcr = BRGPHY_S1000;
+		break;
+	case IFM_100_TX:
+		bmcr = BRGPHY_S100;
+		break;
+	case IFM_10_T:
+	default:
+		bmcr = BRGPHY_S10;
+		break;
+	}
+	if ((media & IFM_GMASK) == IFM_FDX) {
+		bmcr |= BRGPHY_BMCR_FDX;
+		gig = BRGPHY_1000CTL_AFD;
+	} else {
+		gig = BRGPHY_1000CTL_AHD;
+	}
+
+	brgphy_enable_loopback(sc);
+	PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0);
+	PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr);
+	PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE);
+
+	if ((IFM_SUBTYPE(media) != IFM_1000_T) && (IFM_SUBTYPE(media) != IFM_1000_SX))
+		goto brgphy_setmedia_exit;
+
+	PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig);
+	PHY_WRITE(sc, BRGPHY_MII_BMCR,
+	    bmcr | BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
+
+	if (bsc->mii_model != MII_MODEL_xxBROADCOM_BCM5701)
+		goto brgphy_setmedia_exit;
+
+	/*
+	 * When setting the link manually, one side must be the master and
+	 * the other the slave. However ifmedia doesn't give us a good way
+	 * to specify this, so we fake it by using one of the LINK flags.
+	 * If LINK0 is set, we program the PHY to be a master, otherwise
+	 * it's a slave.
+	 */
+	if (master) {
+		PHY_WRITE(sc, BRGPHY_MII_1000CTL,
+		    gig | BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC);
+	} else {
+		PHY_WRITE(sc, BRGPHY_MII_1000CTL,
+		    gig | BRGPHY_1000CTL_MSE);
+	}
+brgphy_setmedia_exit:
+	return;
+}
+
+/* Set the media status based on the PHY settings. */
+/* IFM_FLAG0 = 0 (RX flow control disabled | 1 (enabled) */
+/* IFM_FLAG1 = 0 (TX flow control disabled | 1 (enabled) */
+static void
+brgphy_status(struct mii_softc *sc)
 {
+	struct brgphy_softc *bsc = (struct brgphy_softc *)sc;
 	struct mii_data *mii = sc->mii_pdata;
-	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
-	int bmsr, bmcr;
+	int aux, bmcr, bmsr, anar, anlpar, xstat, val;
+
 
 	mii->mii_media_status = IFM_AVALID;
 	mii->mii_media_active = IFM_ETHER;
 
-	bmsr = PHY_READ(sc, BRGPHY_MII_BMSR);
-	if (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_LINK)
-		mii->mii_media_status |= IFM_ACTIVE;
+	bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR);
+	bmcr = PHY_READ(sc, BRGPHY_MII_BMCR);
+	anar = PHY_READ(sc, BRGPHY_MII_ANAR);
+	anlpar = PHY_READ(sc, BRGPHY_MII_ANLPAR);
 
-	bmcr = PHY_READ(sc, BRGPHY_MII_BMCR);
+	/* Loopback is enabled. */
+	if (bmcr & BRGPHY_BMCR_LOOP) {
 
-	if (bmcr & BRGPHY_BMCR_LOOP)
 		mii->mii_media_active |= IFM_LOOP;
+	}
 
-	if (bmcr & BRGPHY_BMCR_AUTOEN) {
-		if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) {
-			/* Erg, still trying, I guess... */
-			mii->mii_media_active |= IFM_NONE;
-			return;
+	/* Autoneg is still in progress. */
+	if ((bmcr & BRGPHY_BMCR_AUTOEN) &&
+	    (bmsr & BRGPHY_BMSR_ACOMP) == 0) {
+		/* Erg, still trying, I guess... */
+		mii->mii_media_active |= IFM_NONE;
+		goto brgphy_status_exit;
+	}
+
+	/* Autoneg is enabled and complete, link should be up. */
+	if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
+		aux = PHY_READ(sc, BRGPHY_MII_AUXSTS);
+
+		/* If copper link is up, get the negotiated speed/duplex. */
+		if (aux & BRGPHY_AUXSTS_LINK) {
+			mii->mii_media_status |= IFM_ACTIVE;
+			switch (aux & BRGPHY_AUXSTS_AN_RES) {
+			case BRGPHY_RES_1000FD:
+				mii->mii_media_active |= IFM_1000_T | IFM_FDX; 	break;
+			case BRGPHY_RES_1000HD:
+				mii->mii_media_active |= IFM_1000_T | IFM_HDX; 	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 | IFM_HDX; 	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 | IFM_HDX; break;
+			default:
+				mii->mii_media_active |= IFM_NONE; break;
+			}
+		}
+	} else {
+		/* If serdes link is up, get the negotiated speed/duplex. */
+		if (bmsr & BRGPHY_BMSR_LINK) {
+			mii->mii_media_status |= IFM_ACTIVE;
 		}
 
-		switch (PHY_READ(sc, BRGPHY_MII_AUXSTS) &
-		    BRGPHY_AUXSTS_AN_RES) {
-		case BRGPHY_RES_1000FD:
-			mii->mii_media_active |= IFM_1000_T | IFM_FDX;
-			break;
-		case BRGPHY_RES_1000HD:
-			mii->mii_media_active |= IFM_1000_T | IFM_HDX;
-			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 | IFM_HDX;
-			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 | IFM_HDX;
-			break;
-		default:
-			mii->mii_media_active |= IFM_NONE;
-			break;
+		/* Check the link speed/duplex based on the PHY type. */
+		if (bsc->serdes_flags & BRGPHY_5706S) {
+			mii->mii_media_active |= IFM_1000_SX;
+
+			/* If autoneg enabled, read negotiated duplex settings */
+			if (bmcr & BRGPHY_BMCR_AUTOEN) {
+				val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & PHY_READ(sc, BRGPHY_SERDES_ANLPAR);
+				if (val & BRGPHY_SERDES_ANAR_FDX)
+					mii->mii_media_active |= IFM_FDX;
+				else
+					mii->mii_media_active |= IFM_HDX;
+			}
+
+		} else if (bsc->serdes_flags & BRGPHY_5708S) {
+			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
+			xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1);
+
+			/* Todo: Create #defines for hard coded values */
+			switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) {
+			case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: 
+				mii->mii_media_active |= IFM_10_FL; break;
+			case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: 
+				mii->mii_media_active |= IFM_100_FX; break;
+			case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: 
+				mii->mii_media_active |= IFM_1000_SX; break;
+			case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: 
+				mii->mii_media_active |= IFM_2500_SX; break;
+			}
+
+			if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX)
+				mii->mii_media_active |= IFM_FDX;
+			else
+				mii->mii_media_active |= IFM_HDX;
+		}
+	}
+
+#if 0
+	/* Todo: Change bge/bce to use these settings. */
+
+	/* Fetch flow control settings from the PHY */
+	if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
+		/* Set FLAG0 is RX is enabled and FLAG1 if TX is enabled */
+		if ((anar & BRGPHY_ANAR_PC) && (anlpar & BRGPHY_ANLPAR_PC)) {
+			mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1;
+		} else if (!(anar & BRGPHY_ANAR_PC) && (anlpar & BRGPHY_ANAR_ASP) &&
+		    (anlpar & BRPHY_ANLPAR_PC) && (anlpar & BRGPHY_ANLPAR_ASP)) {
+			mii->mii_media_active |= IFM_FLAG1;
+		} else if ((anar & BRGPHY_ANAR_PC) && (anar & BRGPHY_ANAR_ASP) &&
+		    !(anlpar & BRGPHY_ANLPAR_PC) && (anlpar & BRGPHY_ANLPAR_ASP)) {
+			mii->mii_media_active |= IFM_FLAG0;
 		}
-		return;
 	}
+	/* Todo: Add support for fiber settings too. */
+#endif
 
-	mii->mii_media_active = ife->ifm_media;
 
+brgphy_status_exit:
 	return;
 }
 
-
-static int
-brgphy_mii_phy_auto(mii)
-	struct mii_softc *mii;
+static void
+brgphy_mii_phy_auto(struct mii_softc *sc)
 {
+	struct brgphy_softc *bsc = (struct brgphy_softc *)sc;
 	int ktcr = 0;
 
-	brgphy_loop(mii);
-	brgphy_reset(mii);
-	ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD;
-	if (brgphy_mii_model == MII_MODEL_xxBROADCOM_BCM5701)
-		ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC;
-	PHY_WRITE(mii, BRGPHY_MII_1000CTL, ktcr);
-	ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL);
-	DELAY(1000);
-	PHY_WRITE(mii, BRGPHY_MII_ANAR,
-	    BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
-	DELAY(1000);
-	PHY_WRITE(mii, BRGPHY_MII_BMCR,
-	    BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
-	PHY_WRITE(mii, BRGPHY_MII_IMR, 0xFF00);
-	return (EJUSTRETURN);
+	brgphy_reset(sc);
+
+	/* Enable flow control in the advertisement register. */
+	if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
+		/* Pause capability advertisement (pause capable & asymmetric) */
+		PHY_WRITE(sc, BRGPHY_MII_ANAR,
+	    	BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA |
+	    	BRGPHY_ANAR_ASP | BRGPHY_ANAR_PC);
+	} else {
+		PHY_WRITE(sc, BRGPHY_SERDES_ANAR, BRGPHY_SERDES_ANAR_FDX |
+			BRGPHY_SERDES_ANAR_HDX | BRGPHY_SERDES_ANAR_BOTH_PAUSE);
+	}
+
+	/* Enable speed in the 1000baseT control register */
+	ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD;
+	if (bsc->mii_model == MII_MODEL_xxBROADCOM_BCM5701)
+		ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC;
+	PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr);
+	ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL);
+
+	/* Start autonegotiation */
+	PHY_WRITE(sc, BRGPHY_MII_BMCR,BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
+	PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
+
 }
 
+/* Enable loopback to force the link down. */
 static void
-brgphy_loop(struct mii_softc *sc)
+brgphy_enable_loopback(struct mii_softc *sc)
 {
-	u_int32_t bmsr;
 	int i;
 
 	PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP);
 	for (i = 0; i < 15000; i++) {
-		bmsr = PHY_READ(sc, BRGPHY_MII_BMSR);
-		if (!(bmsr & BRGPHY_BMSR_LINK)) {
-#if 0
-			device_printf(sc->mii_dev, "looped %d\n", i);
-#endif
+		if (!(PHY_READ(sc, BRGPHY_MII_BMSR) & BRGPHY_BMSR_LINK))
 			break;
-		}
 		DELAY(10);
 	}
 }
@@ -583,7 +697,24 @@
 }
 
 static void
-bcm5703_load_dspcode(struct mii_softc *sc)
+brgphy_fixup_5704_a0_bug(struct mii_softc *sc)
+{
+	static const struct {
+		int		reg;
+		uint16_t	val;
+	} dspcode[] = {
+		{ 0x1c,				0x8d68 },
+		{ 0x1c,				0x8d68 },
+		{ 0,				0 },
+	};
+	int i;
+
+	for (i = 0; dspcode[i].reg != 0; i++)
+		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
+}
+
+static void
+brgphy_fixup_adc_bug(struct mii_softc *sc)
 {
 	static const struct {
 		int		reg;
@@ -601,14 +732,59 @@
 }
 
 static void
-bcm5704_load_dspcode(struct mii_softc *sc)
+brgphy_fixup_adjust_trim(struct mii_softc *sc)
 {
 	static const struct {
 		int		reg;
-		u_int16_t	val;
+		uint16_t	val;
 	} dspcode[] = {
+		{ BRGPHY_MII_AUXCTL,		0x0c00 },
+		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
+		{ BRGPHY_MII_DSP_RW_PORT,	0x110b },
+		{ BRGPHY_MII_TEST1,			0x0014 },
+		{ BRGPHY_MII_AUXCTL,		0x0400 },
+		{ 0,				0 },
+	};
+	int i;
+
+	for (i = 0; dspcode[i].reg != 0; i++)
+		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
+}
+
+static void
+brgphy_fixup_ber_bug(struct mii_softc *sc)
+{
+	static const struct {
+		int		reg;
+		uint16_t	val;
+	} dspcode[] = {
+		{ BRGPHY_MII_AUXCTL,		0x0c00 },
+		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
+		{ BRGPHY_MII_DSP_RW_PORT,	0x310b },
+		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
+		{ BRGPHY_MII_DSP_RW_PORT,	0x9506 },
+		{ BRGPHY_MII_DSP_ADDR_REG,	0x401f },
+		{ BRGPHY_MII_DSP_RW_PORT,	0x14e2 },
+		{ BRGPHY_MII_AUXCTL,		0x0400 },
+		{ 0,				0 },
+	};
+	int i;
+
+	for (i = 0; dspcode[i].reg != 0; i++)
+		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
+}
+
+static void
+brgphy_fixup_crc_bug(struct mii_softc *sc)
+{
+	static const struct {
+		int		reg;
+		uint16_t	val;
+	} dspcode[] = {
+		{ BRGPHY_MII_DSP_RW_PORT,	0x0a75 },
+		{ 0x1c,				0x8c68 },
 		{ 0x1c,				0x8d68 },
-		{ 0x1c,				0x8d68 },
+		{ 0x1c,				0x8c68 },
 		{ 0,				0 },
 	};
 	int i;
@@ -618,20 +794,16 @@
 }
 
 static void
-bcm5750_load_dspcode(struct mii_softc *sc)
+brgphy_fixup_jitter_bug(struct mii_softc *sc)
 {
 	static const struct {
 		int		reg;
-		u_int16_t	val;
+		uint16_t	val;
 	} dspcode[] = {
-		{ 0x18,				0x0c00 },
-		{ 0x17,				0x000a },
-		{ 0x15,				0x310b },
-		{ 0x17,				0x201f },
-		{ 0x15,				0x9506 },
-		{ 0x17,				0x401f },
-		{ 0x15,				0x14e2 },
-		{ 0x18,				0x0400 },
+		{ BRGPHY_MII_AUXCTL,		0x0c00 },
+		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
+		{ BRGPHY_MII_DSP_RW_PORT,	0x010b },
+		{ BRGPHY_MII_AUXCTL,		0x0400 },
 		{ 0,				0 },
 	};
 	int i;
@@ -641,35 +813,78 @@
 }
 
 static void
+brgphy_ethernet_wirespeed(struct mii_softc *sc)
+{
+	uint32_t	val;
+
+	/* Enable Ethernet at WireSpeed. */
+	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
+	val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
+	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4));
+}
+
+static void
+brgphy_jumbo_settings(struct mii_softc *sc, u_long mtu)
+{
+	struct brgphy_softc *bsc = (struct brgphy_softc *)sc;
+	uint32_t	val;
+
+	/* Set or clear jumbo frame settings in the PHY. */
+	if (mtu > ETHER_MAX_LEN) {
+		if (bsc->mii_model == MII_MODEL_xxBROADCOM_BCM5401) {
+			/* BCM5401 PHY cannot read-modify-write. */
+			PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20);
+		} else {
+			PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
+			val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
+			PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
+			    val | BRGPHY_AUXCTL_LONG_PKT);
+		}
+
+		val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
+		PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
+		    val | BRGPHY_PHY_EXTCTL_HIGH_LA);
+	} else {
+		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
+		val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
+		PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
+		    val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7));
+
+		val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
+		PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 
+			val & ~BRGPHY_PHY_EXTCTL_HIGH_LA);
+	}
+}
+
+static void
 brgphy_reset(struct mii_softc *sc)
 {
-	u_int32_t	val;
-	struct ifnet	*ifp;
-	struct bge_softc	*bge_sc = NULL;
-	struct bce_softc	*bce_sc = NULL;
+	struct brgphy_softc *bsc = (struct brgphy_softc *)sc;
+	struct bge_softc *bge_sc = NULL;
+	struct bce_softc *bce_sc = NULL;
+	struct ifnet *ifp;
 
 	mii_phy_reset(sc);
 
-	switch (brgphy_mii_model) {
-	case MII_MODEL_xxBROADCOM_BCM5400:
-	case MII_MODEL_xxBROADCOM_BCM5401:
-		bcm5401_load_dspcode(sc);
-		break;
-	case MII_MODEL_xxBROADCOM_BCM5411:
-		bcm5411_load_dspcode(sc);
-		break;
-	case MII_MODEL_xxBROADCOM_BCM5703:
-		bcm5703_load_dspcode(sc);
-		break;
-	case MII_MODEL_xxBROADCOM_BCM5704:
-		bcm5704_load_dspcode(sc);
-		break;
-	case MII_MODEL_xxBROADCOM_BCM5750:
-	case MII_MODEL_xxBROADCOM_BCM5714:
-	case MII_MODEL_xxBROADCOM_BCM5780:
-	case MII_MODEL_xxBROADCOM_BCM5706C:
-	case MII_MODEL_xxBROADCOM_BCM5708C:
-		bcm5750_load_dspcode(sc);
+	/* Handle any PHY specific procedures to finish the reset. */
+	switch (bsc->mii_oui) {
+	case MII_OUI_BROADCOM:
+		break;
+	case MII_OUI_xxBROADCOM:
+		switch (bsc->mii_model) {
+		case MII_MODEL_xxBROADCOM_BCM5400:
+			bcm5401_load_dspcode(sc);
+			break;
+		case MII_MODEL_xxBROADCOM_BCM5401:
+			if (bsc->mii_rev == 1 || bsc->mii_rev == 3)
+				bcm5401_load_dspcode(sc);
+			break;
+		case MII_MODEL_xxBROADCOM_BCM5411:
+			bcm5411_load_dspcode(sc);
+			break;
+		}
+		break;
+	case MII_OUI_xxBROADCOM_ALT1:
 		break;
 	}
 
@@ -677,61 +892,102 @@
 
 	/* Find the driver associated with this PHY. */
 	if (strcmp(ifp->if_dname, "bge") == 0)	{
- 		bge_sc = ifp->if_softc;
+		bge_sc = ifp->if_softc;
 	} else if (strcmp(ifp->if_dname, "bce") == 0) {
 		bce_sc = ifp->if_softc;
 	}
 
-	/* Handle any NetXtreme/bge workarounds. */
+	/* Handle any bge (NetXtreme/NetLink) workarounds. */
 	if (bge_sc) {
-	 	/*
+		/* Fix up various bugs */
+		if (bge_sc->bge_flags & BGE_FLAG_5704_A0_BUG)
+			brgphy_fixup_5704_a0_bug(sc);
+		if (bge_sc->bge_flags & BGE_FLAG_ADC_BUG)
+			brgphy_fixup_adc_bug(sc);
+		if (bge_sc->bge_flags & BGE_FLAG_ADJUST_TRIM)
+			brgphy_fixup_adjust_trim(sc);
+		if (bge_sc->bge_flags & BGE_FLAG_BER_BUG)
+			brgphy_fixup_ber_bug(sc);
+		if (bge_sc->bge_flags & BGE_FLAG_CRC_BUG)
+			brgphy_fixup_crc_bug(sc);
+		if (bge_sc->bge_flags & BGE_FLAG_JITTER_BUG)
+			brgphy_fixup_jitter_bug(sc);
+
+		brgphy_jumbo_settings(sc, ifp->if_mtu);
+
+		/*
 		 * Don't enable Ethernet at WireSpeed for the 5700 or the
-		 * 5705 A1 and A2 chips. Make sure we only do this test
-		 * on "bge" NICs, since other drivers may use this same
-		 * PHY subdriver.
+		 * 5705 A1 and A2 chips.
 		 */
-		if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5700 ||
-		    bge_sc->bge_chipid == BGE_CHIPID_BCM5705_A1 ||
-		    bge_sc->bge_chipid == BGE_CHIPID_BCM5705_A2)
-			return;
-
-		/* Enable Ethernet at WireSpeed. */
-		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
-		val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
-		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4));
+		if (bge_sc->bge_asicrev != BGE_ASICREV_BCM5700 &&
+		    bge_sc->bge_chipid != BGE_CHIPID_BCM5705_A1 &&
+		    bge_sc->bge_chipid != BGE_CHIPID_BCM5705_A2)
+			brgphy_ethernet_wirespeed(sc);
 
 		/* Enable Link LED on Dell boxes */
-		if (bge_sc->bge_no_3_led) {
-			PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 
-		    	PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL)
-			    & ~BRGPHY_PHY_EXTCTL_3_LED);
+		if (bge_sc->bge_flags & BGE_FLAG_NO_3LED) {
+			PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
+			    PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) &
+			    ~BRGPHY_PHY_EXTCTL_3_LED);
 		}
+	/* Handle any bce (NetXtreme II) workarounds. */
 	} else if (bce_sc) {
 
-		/* Set or clear jumbo frame settings in the PHY. */
-		if (ifp->if_mtu > ETHER_MAX_LEN) {
-			PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
-			val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
-			PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 
-				val | BRGPHY_AUXCTL_LONG_PKT);
+		if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5708 &&
+			BCE_CHIP_BOND_ID(bce_sc) & BCE_CHIP_BOND_ID_SERDES_BIT) {
 
-			val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
-			PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 
-				val | BRGPHY_PHY_EXTCTL_HIGH_LA);
-		} else {
-			PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
-			val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
-			PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 
-				val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7));
+			/* Store autoneg capabilities/results in digital block (Page 0) */
+			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2);
+			PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, 
+				BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE);
+			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
+
+			/* Enable fiber mode and autodetection */
+			PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, 
+				PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | 
+				BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | 
+				BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE);
+
+			/* Enable parallel detection */
+			PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, 
+				PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | 
+				BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN);
+
+			/* Advertise 2.5G support through next page during autoneg */
+			if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)
+				PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 
+					PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | 
+					BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
+
+			/* Increase TX signal amplitude */
+			if ((BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_A0) ||
+			    (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B0) ||
+			    (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B1)) {
+				PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 
+					BRGPHY_5708S_TX_MISC_PG5);
+				PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, 
+					PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & ~0x30);
+				PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 
+					BRGPHY_5708S_DIG_PG0);
+			}
 
-			val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
-			PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 
-				val & ~BRGPHY_PHY_EXTCTL_HIGH_LA);
+			/* Backplanes use special driver/pre-driver/pre-emphasis values. */
+			if ((bce_sc->bce_shared_hw_cfg & BCE_SHARED_HW_CFG_PHY_BACKPLANE) &&
+				(bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK)) {
+					PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 
+						BRGPHY_5708S_TX_MISC_PG5);
+					PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, 
+						bce_sc->bce_port_hw_cfg & 
+						BCE_PORT_HW_CFG_CFG_TXCTL3_MASK);
+					PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
+						BRGPHY_5708S_DIG_PG0);
+			}
+		} else {
+			brgphy_fixup_ber_bug(sc);
+			brgphy_jumbo_settings(sc, ifp->if_mtu);
+			brgphy_ethernet_wirespeed(sc);
 		}
 
-		/* Enable Ethernet at Wirespeed */
-		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
-		val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
-		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, (val | (1 << 15) | (1 << 4)));
 	}
 }
+


More information about the Midnightbsd-cvs mailing list