diff options
-rw-r--r-- | sys/pci/if_xl.c | 72 |
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. */ |