Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Nov 2012 02:31:28 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r243536 - stable/9/sys/dev/bge
Message-ID:  <201211260231.qAQ2VSJ2073039@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Mon Nov 26 02:31:28 2012
New Revision: 243536
URL: http://svnweb.freebsd.org/changeset/base/243536

Log:
  MFC r241215-241216,241219-241220,241341,241343:
  r241215:
    Don't touch EMAC Mode and TX/RX MAC Mode register when driver is
    not running.
  
  r241216:
    APE firmware touches EMAC Mode and TX/RX MAC Mode registers to keep
    the MAC connected to the outside world.  So keep the accesses
    atomic.
  
  r241219:
    Add 40 microseconds delay after updating EMAC Mode register as
    recommended by Broadcom data sheet.
  
  r241220:
    Follow Broadcom datasheet:
     Delay 100 microseconds after enabling transmit MAC.
     Delay 10 microseconds after enabling receive MAC.
  
  r241341:
    Limit applying TX data corruption and FIFO workaround to BCM5719
    A0. It's believed BCM5720 does not have the issue.
  
  r241343:
    Rework device detach. While here, move driver lock/callout
    initialization to the beginning of device attach for readability.

Modified:
  stable/9/sys/dev/bge/if_bge.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)

Modified: stable/9/sys/dev/bge/if_bge.c
==============================================================================
--- stable/9/sys/dev/bge/if_bge.c	Mon Nov 26 02:04:11 2012	(r243535)
+++ stable/9/sys/dev/bge/if_bge.c	Mon Nov 26 02:31:28 2012	(r243536)
@@ -896,7 +896,11 @@ bge_miibus_statchg(device_t dev)
 {
 	struct bge_softc *sc;
 	struct mii_data *mii;
+	uint32_t mac_mode, rx_mode, tx_mode;
+
 	sc = device_get_softc(dev);
+	if ((sc->bge_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
 	mii = device_get_softc(sc->bge_miibus);
 
 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
@@ -922,30 +926,40 @@ bge_miibus_statchg(device_t dev)
 		sc->bge_link = 0;
 	if (sc->bge_link == 0)
 		return;
-	BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_PORTMODE);
+
+	/*
+	 * APE firmware touches these registers to keep the MAC
+	 * connected to the outside world.  Try to keep the
+	 * accesses atomic.
+	 */
+
+	/* Set the port mode (MII/GMII) to match the link speed. */
+	mac_mode = CSR_READ_4(sc, BGE_MAC_MODE) &
+	    ~(BGE_MACMODE_PORTMODE | BGE_MACMODE_HALF_DUPLEX);
+	tx_mode = CSR_READ_4(sc, BGE_TX_MODE);
+	rx_mode = CSR_READ_4(sc, BGE_RX_MODE);
+
 	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
 	    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)
-		BGE_SETBIT(sc, BGE_MAC_MODE, BGE_PORTMODE_GMII);
+		mac_mode |= BGE_PORTMODE_GMII;
 	else
-		BGE_SETBIT(sc, BGE_MAC_MODE, BGE_PORTMODE_MII);
+		mac_mode |= BGE_PORTMODE_MII;
 
+	/* Set MAC flow control behavior to match link flow control settings. */
+	tx_mode &= ~BGE_TXMODE_FLOWCTL_ENABLE;
+	rx_mode &= ~BGE_RXMODE_FLOWCTL_ENABLE;
 	if (IFM_OPTIONS(mii->mii_media_active & IFM_FDX) != 0) {
-		BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX);
-		if ((IFM_OPTIONS(mii->mii_media_active) &
-		    IFM_ETH_TXPAUSE) != 0)
-			BGE_SETBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE);
-		else
-			BGE_CLRBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE);
-		if ((IFM_OPTIONS(mii->mii_media_active) &
-		    IFM_ETH_RXPAUSE) != 0)
-			BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE);
-		else
-			BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE);
-	} else {
-		BGE_SETBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX);
-		BGE_CLRBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE);
-		BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE);
-	}
+		if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
+			tx_mode |= BGE_TXMODE_FLOWCTL_ENABLE;
+		if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
+			rx_mode |= BGE_RXMODE_FLOWCTL_ENABLE;
+	} else
+		mac_mode |= BGE_MACMODE_HALF_DUPLEX;
+
+	CSR_WRITE_4(sc, BGE_MAC_MODE, mac_mode);
+	DELAY(40);
+	CSR_WRITE_4(sc, BGE_TX_MODE, tx_mode);
+	CSR_WRITE_4(sc, BGE_RX_MODE, rx_mode);
 }
 
 /*
@@ -1421,6 +1435,7 @@ bge_chipinit(struct bge_softc *sc)
 
 	/* Clear the MAC control register */
 	CSR_WRITE_4(sc, BGE_MAC_MODE, 0);
+	DELAY(40);
 
 	/*
 	 * Clear the MAC statistics block in the NIC's
@@ -2033,6 +2048,7 @@ bge_blockinit(struct bge_softc *sc)
 
 	/* Turn on DMA, clear stats */
 	CSR_WRITE_4(sc, BGE_MAC_MODE, val);
+	DELAY(40);
 
 	/* Set misc. local control, enable interrupts on attentions */
 	CSR_WRITE_4(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_ONATTN);
@@ -2105,8 +2121,8 @@ bge_blockinit(struct bge_softc *sc)
 		 * Adjust tx margin to prevent TX data corruption and
 		 * fix internal FIFO overflow.
 		 */
-		if (sc->bge_asicrev == BGE_ASICREV_BCM5719 ||
-		    sc->bge_asicrev == BGE_ASICREV_BCM5720) {
+		if (sc->bge_asicrev == BGE_ASICREV_BCM5719 &&
+		    sc->bge_chipid == BGE_CHIPID_BCM5719_A0) {
 			dmactl &= ~(BGE_RDMA_RSRVCTRL_FIFO_LWM_MASK |
 			    BGE_RDMA_RSRVCTRL_FIFO_HWM_MASK |
 			    BGE_RDMA_RSRVCTRL_TXMRGN_MASK);
@@ -2884,7 +2900,9 @@ bge_attach(device_t dev)
 	sc = device_get_softc(dev);
 	sc->bge_dev = dev;
 
+	BGE_LOCK_INIT(sc, device_get_nameunit(dev));
 	TASK_INIT(&sc->bge_intr_task, 0, bge_intr_task, sc);
+	callout_init_mtx(&sc->bge_stat_ch, &sc->bge_mtx, 0);
 
 	/*
 	 * Map control/status registers.
@@ -3243,8 +3261,6 @@ bge_attach(device_t dev)
 
 	bge_devinfo(sc);
 
-	BGE_LOCK_INIT(sc, device_get_nameunit(dev));
-
 	/* Try to reset the chip. */
 	if (bge_reset(sc)) {
 		device_printf(sc->bge_dev, "chip reset failed\n");
@@ -3448,7 +3464,6 @@ again:
 	 * Call MI attach routine.
 	 */
 	ether_ifattach(ifp, eaddr);
-	callout_init_mtx(&sc->bge_stat_ch, &sc->bge_mtx, 0);
 
 	/* Tell upper layer we support long frames. */
 	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
@@ -3465,7 +3480,7 @@ again:
 		if (sc->bge_tq == NULL) {
 			device_printf(dev, "could not create taskqueue.\n");
 			ether_ifdetach(ifp);
-			error = ENXIO;
+			error = ENOMEM;
 			goto fail;
 		}
 		taskqueue_start_threads(&sc->bge_tq, 1, PI_NET, "%s taskq",
@@ -3473,23 +3488,19 @@ again:
 		error = bus_setup_intr(dev, sc->bge_irq,
 		    INTR_TYPE_NET | INTR_MPSAFE, bge_msi_intr, NULL, sc,
 		    &sc->bge_intrhand);
-		if (error)
-			ether_ifdetach(ifp);
 	} else
 		error = bus_setup_intr(dev, sc->bge_irq,
 		    INTR_TYPE_NET | INTR_MPSAFE, NULL, bge_intr, sc,
 		    &sc->bge_intrhand);
 
 	if (error) {
-		bge_detach(dev);
+		ether_ifdetach(ifp);
 		device_printf(sc->bge_dev, "couldn't set up irq\n");
 	}
 
-	return (0);
-
 fail:
-	bge_release_resources(sc);
-
+	if (error)
+		bge_detach(dev);
 	return (error);
 }
 
@@ -3507,16 +3518,16 @@ bge_detach(device_t dev)
 		ether_poll_deregister(ifp);
 #endif
 
-	BGE_LOCK(sc);
-	bge_stop(sc);
-	bge_reset(sc);
-	BGE_UNLOCK(sc);
-
-	callout_drain(&sc->bge_stat_ch);
+	if (device_is_attached(dev)) {
+		ether_ifdetach(ifp);
+		BGE_LOCK(sc);
+		bge_stop(sc);
+		BGE_UNLOCK(sc);
+		callout_drain(&sc->bge_stat_ch);
+	}
 
 	if (sc->bge_tq)
 		taskqueue_drain(sc->bge_tq, &sc->bge_intr_task);
-	ether_ifdetach(ifp);
 
 	if (sc->bge_flags & BGE_FLAG_TBI) {
 		ifmedia_removeall(&sc->bge_ifmedia);
@@ -3764,6 +3775,7 @@ bge_reset(struct bge_softc *sc)
 		BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
 
 	CSR_WRITE_4(sc, BGE_MAC_MODE, 0);
+	DELAY(40);
 
 	/*
 	 * The 5704 in TBI mode apparently needs some special
@@ -5041,9 +5053,11 @@ bge_init_locked(struct bge_softc *sc)
 	}
 	/* Turn on transmitter. */
 	CSR_WRITE_4(sc, BGE_TX_MODE, mode | BGE_TXMODE_ENABLE);
+	DELAY(100);
 
 	/* Turn on receiver. */
 	BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE);
+	DELAY(10);
 
 	/*
 	 * Set the number of good frames to receive after RX MBUF
@@ -5079,11 +5093,11 @@ bge_init_locked(struct bge_softc *sc)
 	bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
 	}
 
-	bge_ifmedia_upd_locked(ifp);
-
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
+	bge_ifmedia_upd_locked(ifp);
+
 	callout_reset(&sc->bge_stat_ch, hz, bge_tick, sc);
 }
 
@@ -5160,6 +5174,7 @@ bge_ifmedia_upd_locked(struct ifnet *ifp
 				BGE_SETBIT(sc, BGE_MAC_MODE,
 				    BGE_MACMODE_HALF_DUPLEX);
 			}
+			DELAY(40);
 			break;
 		default:
 			return (EINVAL);
@@ -5635,9 +5650,11 @@ bge_link_upd(struct bge_softc *sc)
 		if (status & BGE_MACSTAT_TBI_PCS_SYNCHED) {
 			if (!sc->bge_link) {
 				sc->bge_link++;
-				if (sc->bge_asicrev == BGE_ASICREV_BCM5704)
+				if (sc->bge_asicrev == BGE_ASICREV_BCM5704) {
 					BGE_CLRBIT(sc, BGE_MAC_MODE,
 					    BGE_MACMODE_TBI_SEND_CFGS);
+					DELAY(40);
+				}
 				CSR_WRITE_4(sc, BGE_MAC_STS, 0xFFFFFFFF);
 				if (bootverbose)
 					if_printf(sc->bge_ifp, "link UP\n");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211260231.qAQ2VSJ2073039>