summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/pci/if_xl.c72
1 files changed, 68 insertions, 4 deletions
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c
index e818b82..7b24cad 100644
--- a/sys/pci/if_xl.c
+++ b/sys/pci/if_xl.c
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: if_xl.c,v 1.9 1998/09/04 16:22:15 wpaul Exp $
+ * $Id: if_xl.c,v 1.53 1998/09/08 16:05:04 wpaul Exp $
*/
/*
@@ -123,11 +123,31 @@
*/
#define XL_USEIOSPACE
+/*
+ * This #define controls the behavior of autonegotiation during the
+ * bootstrap phase. It's possible to have the driver initiate an
+ * autonegotiation session and then set a timeout which will cause the
+ * autoneg results to be polled later, usually once the kernel has
+ * finished booting. This is clever and all, but it can have bad side
+ * effects in some cases, particularly where NFS is involved. For
+ * example, if we're booting diskless with an NFS rootfs, the network
+ * interface has to be up and running before we hit the mountroot()
+ * code, otherwise mounting the rootfs will fail and we'll probably
+ * panic.
+ *
+ * Consequently, the 'backgrounded' autoneg behavior is turned off
+ * by default and we actually sit and wait 5 seconds for autonegotiation
+ * to complete before proceeding with the other device probes. If you
+ * choose to use the other behavior, you can uncomment this #define and
+ * recompile.
+ */
+/* #define XL_BACKGROUND_AUTONEG */
+
#include <pci/if_xlreg.h>
#ifndef lint
static char rcsid[] =
- "$Id: if_xl.c,v 1.9 1998/09/04 16:22:15 wpaul Exp $";
+ "$Id: if_xl.c,v 1.53 1998/09/08 16:05:04 wpaul Exp $";
#endif
/*
@@ -777,7 +797,7 @@ static void xl_autoneg_mii(sc, flag, verbose)
* is really bad manners.
*/
xl_autoneg_xmit(sc);
- DELAY(3000000);
+ DELAY(5000000);
break;
case XL_FLAG_SCHEDDELAY:
/*
@@ -968,6 +988,20 @@ static void xl_setmode_mii(sc, media)
{
u_int16_t bmcr;
u_int32_t icfg;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /*
+ * If an autoneg session is in progress, stop it.
+ */
+ if (sc->xl_autoneg) {
+ printf("xl%d: canceling autoneg session\n", sc->xl_unit);
+ ifp->if_timer = sc->xl_autoneg = sc->xl_want_auto = 0;
+ bmcr = xl_phy_readreg(sc, PHY_BMCR);
+ bmcr &= ~PHY_BMCR_AUTONEGENBL;
+ xl_phy_writereg(sc, PHY_BMCR, bmcr);
+ }
printf("xl%d: selecting MII, ", sc->xl_unit);
@@ -1582,12 +1616,20 @@ xl_attach(config_id, unit)
break;
case XL_XCVR_AUTO:
media = IFM_ETHER|IFM_AUTO;
+#ifdef XL_BACKGROUND_AUTONEG
xl_autoneg_mii(sc, XL_FLAG_SCHEDDELAY, 1);
+#else
+ xl_autoneg_mii(sc, XL_FLAG_FORCEDELAY, 1);
+#endif
break;
case XL_XCVR_100BTX:
case XL_XCVR_MII:
media = sc->ifmedia.ifm_media;
+#ifdef XL_BACKGROUND_AUTONEG
xl_autoneg_mii(sc, XL_FLAG_SCHEDDELAY, 1);
+#else
+ xl_autoneg_mii(sc, XL_FLAG_FORCEDELAY, 1);
+#endif
break;
case XL_XCVR_100BFX:
media = IFM_ETHER|IFM_100_FX;
@@ -1595,6 +1637,11 @@ xl_attach(config_id, unit)
default:
printf("xl%d: unknown XCVR type: %d\n", sc->xl_unit,
sc->xl_xcvr);
+ /*
+ * This will probably be wrong, but it prevents
+ * the ifmedia code from panicking.
+ */
+ media = IFM_ETHER|IFM_10_T;
break;
}
@@ -1876,7 +1923,8 @@ static void xl_txeof(sc)
if (sc->xl_want_auto)
xl_autoneg_mii(sc, XL_FLAG_SCHEDDELAY, 1);
} else {
- if (CSR_READ_4(sc, XL_DMACTL) & XL_DMACTL_DOWN_STALLED) {
+ if (CSR_READ_4(sc, XL_DMACTL) & XL_DMACTL_DOWN_STALLED ||
+ !CSR_READ_4(sc, XL_DOWNLIST_PTR)) {
CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
vtophys(sc->xl_cdata.xl_tx_head->xl_ptr));
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
@@ -2144,6 +2192,22 @@ static void xl_start(ifp)
}
/*
+ * If the OACTIVE flag is set, make sure the transmitter
+ * isn't wedged. Call the txeoc handler to make sure the
+ * transmitter is enabled and then call the txeof handler
+ * to see if any descriptors can be reclaimed and reload
+ * the downlist pointer register if necessary. If after
+ * that the OACTIVE flag is still set, return, otherwise
+ * proceed and queue up some more frames.
+ */
+ if (ifp->if_flags & IFF_OACTIVE) {
+ xl_txeoc(sc);
+ xl_txeof(sc);
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+ }
+
+ /*
* Check for an available queue slot. If there are none,
* punt.
*/
OpenPOWER on IntegriCloud