kern/50644: [PATCH] Update xe driver: multicast, hardware setup, etc.

Scott Mitchell scott+freebsd at fishballoon.org
Sun Apr 6 09:00:32 PDT 2003


>Number:         50644
>Category:       kern
>Synopsis:       [PATCH] Update xe driver: multicast, hardware setup, etc.
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Apr 06 09:00:28 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator:     Scott Mitchell
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
>Environment:
System: FreeBSD orac 5.0-CURRENT FreeBSD 5.0-CURRENT #0: Sun Apr  6 14:00:33 BST 2003     scott at tuatara:/local/0/obj/local/0/-CURRENT/src/sys/ORAC  i386

>Description:
The xe driver is in dire need of some maintenance :-)  The attached patch is
the first of several I have planned.  This one:
	- Fixes the hardware initialisation to eliminate the watchdog timeout
	  every time the card is powered up.
	- Add multicast support (apparently this had never worked).
	- Enable 'early transmit' mode on CE3-class hardware.  This may improve
	  performance, assuming the card can be fed fast enough.
	- Clean up handling of MAC interrupts and statistics in ISR.
	- Some general code cleanup.

The next stage will be to improve the detection and handling of CE2-class
cards, which have also never really worked.  I'm releasing this work in
progress in the hope that people will test it and confirm that I haven't
broken anything -- any card that worked before should continue to work,
hopefully with fewer complaints.

>How-To-Repeat:

>Fix:
Index: src/sys/dev/xe/if_xe.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/xe/if_xe.c,v
retrieving revision 1.36
retrieving revision 1.35.10000.3
diff -c -r1.36 -r1.35.10000.3
*** src/sys/dev/xe/if_xe.c	19 Feb 2003 05:47:17 -0000	1.36
--- src/sys/dev/xe/if_xe.c	6 Apr 2003 15:06:24 -0000	1.35.10000.3
***************
*** 1,5 ****
  /*-
!  * Copyright (c) 1998, 1999 Scott Mitchell
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
--- 1,5 ----
  /*-
!  * Copyright (c) 1998, 1999, 2003  Scott Mitchell
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
***************
*** 24,39 ****
   * SUCH DAMAGE.
   *
   *	$Id: if_xe.c,v 1.20 1999/06/13 19:17:40 scott Exp $
!  * $FreeBSD: src/sys/dev/xe/if_xe.c,v 1.36 2003/02/19 05:47:17 imp Exp $
!  */
! 
! /*
!  * XXX TODO XXX
!  *
!  * I've pushed this fairly far, but there are some things that need to be
!  * done here.  I'm documenting them here in case I get destracted. -- imp
!  *
!  * xe_cem56fix -- need to figure out how to map the extra stuff.
   */
  
  /*
--- 24,30 ----
   * SUCH DAMAGE.
   *
   *	$Id: if_xe.c,v 1.20 1999/06/13 19:17:40 scott Exp $
!  * $FreeBSD: src/sys/dev/xe/if_xe.c,v 1.35.10000.3 2003/04/06 15:06:24 scott Exp $
   */
  
  /*
***************
*** 97,110 ****
   * the CEM56/REM56 support code; and the FreeBSD UK Users' Group for hosting
   * the web pages.
   *
-  * Contact points:
-  *
-  * Driver web page: http://ukug.uk.freebsd.org/~scott/xe_drv/
-  *
-  * Mailing list: http://www.lovett.com/lists/freebsd-xircom/
-  * or send "subscribe freebsd-xircom" to <majordomo at lovett.com>
-  *
   * Author email: <scott at uk.freebsd.org>
   */
  
  
--- 88,95 ----
   * the CEM56/REM56 support code; and the FreeBSD UK Users' Group for hosting
   * the web pages.
   *
   * Author email: <scott at uk.freebsd.org>
+  * Driver web page: http://ukug.uk.freebsd.org/~scott/xe_drv/
   */
  
  
***************
*** 157,162 ****
--- 142,151 ----
  #define XE_AUTONEG_100TX	3	/* Trying to force 100baseTX link */
  #define XE_AUTONEG_FAIL		4	/* Autonegotiation failed */
  
+ /*
+  * Multicast hashing CRC constants
+  */
+ #define XE_CRC_POLY  0x04c11db6
  
  /*
   * Prototypes start here
***************
*** 168,183 ****
  static int       xe_media_change	(struct ifnet *ifp);
  static void      xe_media_status	(struct ifnet *ifp, struct ifmediareq *mrp);
  static timeout_t xe_setmedia;
! static void      xe_hard_reset		(struct xe_softc *scp);
! static void      xe_soft_reset		(struct xe_softc *scp);
  static void      xe_stop		(struct xe_softc *scp);
  static void      xe_enable_intr		(struct xe_softc *scp);
  static void      xe_disable_intr	(struct xe_softc *scp);
! static void      xe_setmulti		(struct xe_softc *scp);
! static void      xe_setaddrs		(struct xe_softc *scp);
  static int       xe_pio_write_packet	(struct xe_softc *scp, struct mbuf *mbp);
- static u_int32_t xe_compute_crc		(u_int8_t *data, int len) __unused;
- static int       xe_compute_hashbit	(u_int32_t crc) __unused;
  
  /*
   * MII functions
--- 157,170 ----
  static int       xe_media_change	(struct ifnet *ifp);
  static void      xe_media_status	(struct ifnet *ifp, struct ifmediareq *mrp);
  static timeout_t xe_setmedia;
! static void      xe_reset		(struct xe_softc *scp);
  static void      xe_stop		(struct xe_softc *scp);
  static void      xe_enable_intr		(struct xe_softc *scp);
  static void      xe_disable_intr	(struct xe_softc *scp);
! static void      xe_set_multicast	(struct xe_softc *scp);
! static void      xe_set_addr		(struct xe_softc *scp, u_int8_t* addr, unsigned idx);
! static void      xe_set_hash		(struct xe_softc *scp, u_int8_t* addr);
  static int       xe_pio_write_packet	(struct xe_softc *scp, struct mbuf *mbp);
  
  /*
   * MII functions
***************
*** 190,201 ****
  static u_int16_t xe_phy_readreg		(struct xe_softc *scp, u_int16_t reg);
  static void      xe_phy_writereg	(struct xe_softc *scp, u_int16_t reg, u_int16_t data);
  
  /*
!  * Debug functions -- uncomment for VERY verbose dignostic information.
!  * Set to 1 for less verbose information
   */
! /* #define XE_DEBUG 2 */
! #ifdef XE_DEBUG
  #define XE_REG_DUMP(scp)		xe_reg_dump((scp))
  #define XE_MII_DUMP(scp)		xe_mii_dump((scp))
  static void      xe_reg_dump		(struct xe_softc *scp);
--- 177,192 ----
  static u_int16_t xe_phy_readreg		(struct xe_softc *scp, u_int16_t reg);
  static void      xe_phy_writereg	(struct xe_softc *scp, u_int16_t reg, u_int16_t data);
  
+ 
  /*
!  * Debug logging level (comment out for normal operation):
!  * 1 = Log more hardware details, xe_ioctl details
!  * 2 = Log most function calls, some (eg. multicast, MII) in detail
!  * 3 = Log everything, including all interrupts and packets sent
   */
! #define XE_DEBUG 0
! 
! #if XE_DEBUG > 2
  #define XE_REG_DUMP(scp)		xe_reg_dump((scp))
  #define XE_MII_DUMP(scp)		xe_mii_dump((scp))
  static void      xe_reg_dump		(struct xe_softc *scp);
***************
*** 205,210 ****
--- 196,202 ----
  #define XE_MII_DUMP(scp)
  #endif
  
+ 
  /*
   * Attach a device.
   */
***************
*** 213,232 ****
  {
    struct xe_softc *scp = device_get_softc(dev);
  
! #ifdef XE_DEBUG
    device_printf(dev, "attach\n");
  #endif
  
!   /* Fill in some private data */
    scp->ifp = &scp->arpcom.ac_if;
    scp->ifm = &scp->ifmedia;
!   scp->autoneg_status = 0;
  
-   /* Hopefully safe to read this here */
-   XE_SELECT_PAGE(4);
-   scp->version = XE_INB(XE_BOV);
- 
-   scp->dev = dev;
    /* Initialise the ifnet structure */
    if (!scp->ifp->if_name) {
      scp->ifp->if_softc = scp;
--- 205,220 ----
  {
    struct xe_softc *scp = device_get_softc(dev);
  
! #if XE_DEBUG > 1
    device_printf(dev, "attach\n");
  #endif
  
!   /* Initialise stuff... */
!   scp->dev = dev;
    scp->ifp = &scp->arpcom.ac_if;
    scp->ifm = &scp->ifmedia;
!   scp->autoneg_status = XE_AUTONEG_NONE;
  
    /* Initialise the ifnet structure */
    if (!scp->ifp->if_name) {
      scp->ifp->if_softc = scp;
***************
*** 241,246 ****
--- 229,235 ----
      scp->ifp->if_ioctl = xe_ioctl;
      scp->ifp->if_watchdog = xe_watchdog;
      scp->ifp->if_init = xe_init;
+     scp->ifp->if_baudrate = 100000000;
      scp->ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
    }
  
***************
*** 248,291 ****
    ifmedia_init(scp->ifm, 0, xe_media_change, xe_media_status);
    callout_handle_init(&scp->chand);
  
!   /*
!    * Fill in supported media types.  Some cards _do_ support full duplex
!    * operation, but this driver doesn't, yet.  Therefore we leave those modes
!    * out of the list.  We support some form of autoselection in all cases.
!    */
    if (scp->mohawk) {
      ifmedia_add(scp->ifm, IFM_ETHER|IFM_100_TX, 0, NULL);
!     ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T, 0, NULL);
    }
!   else {
!     ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T, 0, NULL);
      ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_2, 0, NULL);
-   }
    ifmedia_add(scp->ifm, IFM_ETHER|IFM_AUTO, 0, NULL);
  
    /* Default is to autoselect best supported media type */
    ifmedia_set(scp->ifm, IFM_ETHER|IFM_AUTO);
  
    /* Print some useful information */
!   device_printf(dev, "%s %s, bonding version %#x%s%s\n",
  	 scp->vendor,
  	 scp->card_type,
  	 scp->version,
  	 scp->mohawk ? ", 100Mbps capable" : "",
  	 scp->modem ?  ", with modem"      : "");
    if (scp->mohawk) {
      XE_SELECT_PAGE(0x10);
!     device_printf(dev, "DingoID = %#x, RevisionID = %#x, VendorID = %#x\n",
  	   XE_INW(XE_DINGOID),
  	   XE_INW(XE_RevID),
  	   XE_INW(XE_VendorID));
    }
    if (scp->ce2) {
      XE_SELECT_PAGE(0x45);
!     device_printf(dev, "CE2 version = %#x\n", XE_INB(XE_REV));
    }
! 
!   /* Print MAC address */
    device_printf(dev, "Ethernet address %6D\n", scp->arpcom.ac_enaddr, ":");
  
    /* Attach the interface */
--- 237,288 ----
    ifmedia_init(scp->ifm, 0, xe_media_change, xe_media_status);
    callout_handle_init(&scp->chand);
  
!   /* Add supported media types */
    if (scp->mohawk) {
      ifmedia_add(scp->ifm, IFM_ETHER|IFM_100_TX, 0, NULL);
!     ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
!     ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
    }
!   ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T, 0, NULL);
!   if (scp->ce2)
      ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_2, 0, NULL);
    ifmedia_add(scp->ifm, IFM_ETHER|IFM_AUTO, 0, NULL);
  
    /* Default is to autoselect best supported media type */
    ifmedia_set(scp->ifm, IFM_ETHER|IFM_AUTO);
  
+   /* Get the hardware into a known state */
+   xe_reset(scp);
+ 
+   /* Get hardware version numbers */
+   XE_SELECT_PAGE(4);
+   scp->version = XE_INB(XE_BOV);
+   if (scp->mohawk)
+     scp->srev = (XE_INB(XE_BOV) & 0x70) >> 4;
+   else
+     scp->srev = (XE_INB(XE_BOV) & 0x30) >> 4;
+ 
    /* Print some useful information */
!   device_printf(dev, "%s %s, version 0x%02x/0x%02x%s%s\n",
  	 scp->vendor,
  	 scp->card_type,
  	 scp->version,
+ 	 scp->srev,
  	 scp->mohawk ? ", 100Mbps capable" : "",
  	 scp->modem ?  ", with modem"      : "");
+ #if XE_DEBUG > 0
    if (scp->mohawk) {
      XE_SELECT_PAGE(0x10);
!     device_printf(dev, "DingoID=0x%04x, RevisionID=0x%04x, VendorID=0x%04x\n",
  	   XE_INW(XE_DINGOID),
  	   XE_INW(XE_RevID),
  	   XE_INW(XE_VendorID));
    }
    if (scp->ce2) {
      XE_SELECT_PAGE(0x45);
!     device_printf(dev, "CE2 version = 0x%#02x\n", XE_INB(XE_REV));
    }
! #endif
    device_printf(dev, "Ethernet address %6D\n", scp->arpcom.ac_enaddr, ":");
  
    /* Attach the interface */
***************
*** 297,401 ****
  
  
  /*
!  * Initialize device.  Completes the reset procedure on the card and starts
!  * output.  If there's an autonegotiation in progress we DON'T do anything;
!  * the media selection code will call us again when it's done.
   */
  static void
  xe_init(void *xscp) {
    struct xe_softc *scp = xscp;
    int s;
  
! #ifdef XE_DEBUG
    device_printf(scp->dev, "init\n");
  #endif
  
!   if (TAILQ_EMPTY(&scp->ifp->if_addrhead)) return;
  
    /* Reset transmitter flags */
    scp->tx_queued = 0;
    scp->tx_tpr = 0;
!   scp->tx_collisions = 0;
    scp->ifp->if_timer = 0;
  
!   s = splimp();
  
    XE_SELECT_PAGE(0x42);
!   XE_OUTB(XE_SWC0, 0x20);	/* Disable source insertion (WTF is that?) */
  
!   /*
!    * Set the 'local memory dividing line' -- splits the 32K card memory into
!    * 8K for transmit buffers and 24K for receive.  This is done automatically
!    * on newer revision cards.
!    */
    if (scp->srev != 1) {
      XE_SELECT_PAGE(2);
      XE_OUTW(XE_RBS, 0x2000);
    }
  
    /* Set up multicast addresses */
!   xe_setmulti(scp);
  
!   /* Fix the data offset register -- reset leaves it off-by-one */
    XE_SELECT_PAGE(0);
    XE_OUTW(XE_DO, 0x2000);
  
!   /*
!    * Set MAC interrupt masks and clear status regs.  The bit names are direct
!    * from the Linux code; I have no idea what most of them do.
!    */
!   XE_SELECT_PAGE(0x40);		/* Bit 7..0 */
!   XE_OUTB(XE_RX0Msk, 0xff);	/* ROK, RAB, rsv, RO,  CRC, AE,  PTL, MP  */
!   XE_OUTB(XE_TX0Msk, 0xff);	/* TOK, TAB, SQE, LL,  TU,  JAB, EXC, CRS */
!   XE_OUTB(XE_TX0Msk+1, 0xb0);	/* rsv, rsv, PTD, EXT, rsv, rsv, rsv, rsv */
!   XE_OUTB(XE_RST0, 0x00);	/* ROK, RAB, REN, RO,  CRC, AE,  PTL, MP  */
!   XE_OUTB(XE_TXST0, 0x00);	/* TOK, TAB, SQE, LL,  TU,  JAB, EXC, CRS */
!   XE_OUTB(XE_TXST1, 0x00);	/* TEN, rsv, PTD, EXT, retry_counter:4    */
  
!   /*
!    * Check for an in-progress autonegotiation.  If one is active, just set
!    * IFF_RUNNING and return.  The media selection code will call us again when 
!    * it's done.
!    */
!   if (scp->autoneg_status) {
!     scp->ifp->if_flags |= IFF_RUNNING;
!   }
!   else {
!     /* Enable receiver, put MAC online */
!     XE_SELECT_PAGE(0x40);
!     XE_OUTB(XE_CMD0, XE_CMD0_RX_ENABLE|XE_CMD0_ONLINE);
  
!     /* Set up IMR, enable interrupts */
!     xe_enable_intr(scp);
  
!     /* Attempt to start output */
!     scp->ifp->if_flags |= IFF_RUNNING;
!     scp->ifp->if_flags &= ~IFF_OACTIVE;
!     xe_start(scp->ifp);
!   }
  
    (void)splx(s);
  }
  
  
  /*
!  * Start output on interface.  We make two assumptions here:
!  *  1) that the current priority is set to splimp _before_ this code
!  *     is called *and* is returned to the appropriate priority after
!  *     return
!  *  2) that the IFF_OACTIVE flag is checked before this code is called
!  *     (i.e. that the output part of the interface is idle)
   */
  static void
  xe_start(struct ifnet *ifp) {
    struct xe_softc *scp = ifp->if_softc;
    struct mbuf *mbp;
  
    /*
     * Loop while there are packets to be sent, and space to send them.
     */
    while (1) {
!     IF_DEQUEUE(&ifp->if_snd, mbp);	/* Suck a packet off the send queue */
  
      if (mbp == NULL) {
        /*
--- 294,445 ----
  
  
  /*
!  * Complete hardware intitialisation and enable output.  Exits without doing
!  * anything if there's no address assigned to the card, or if media selection
!  * is in progress (the latter implies we've already run this function).
   */
  static void
  xe_init(void *xscp) {
    struct xe_softc *scp = xscp;
+   unsigned i;
    int s;
  
!   if (TAILQ_EMPTY(&scp->ifp->if_addrhead)) return;
! 
!   if (scp->autoneg_status != XE_AUTONEG_NONE) return;
! 
! #if XE_DEBUG > 1
    device_printf(scp->dev, "init\n");
  #endif
  
!   s = splimp();
  
    /* Reset transmitter flags */
    scp->tx_queued = 0;
    scp->tx_tpr = 0;
!   scp->tx_timeouts = 0;
!   scp->tx_thres = 64;
    scp->ifp->if_timer = 0;
  
!   /* Soft reset the card */
!   XE_SELECT_PAGE(0);
!   XE_OUTB(XE_CR, XE_CR_SOFT_RESET);
!   DELAY(40000);
!   XE_OUTB(XE_CR, 0);
!   DELAY(40000);
  
+   if (scp->mohawk) {
+     /*
+      * set GP1 and GP2 as outputs (bits 2 & 3)
+      * set GP1 low to power on the ML6692 (bit 0)
+      * set GP2 high to power on the 10Mhz chip (bit 1)
+      */
+     XE_SELECT_PAGE(4);
+     XE_OUTB(XE_GPR0, XE_GPR0_GP2_SELECT|XE_GPR0_GP1_SELECT|XE_GPR0_GP2_OUT);
+   }
+ 
+   /* Shut off interrupts */
+   xe_disable_intr(scp);
+ 
+   /* Wait for everything to wake up */
+   DELAY(500000);
+ 
+   /* Check for PHY */
+   if (scp->mohawk)
+     scp->phy_ok = xe_mii_init(scp);
+ 
+   /* Disable 'source insertion' (not sure what that means) */
    XE_SELECT_PAGE(0x42);
!   XE_OUTB(XE_SWC0, XE_SWC0_NO_SRC_INSERT);
  
!   /* Set 8K/24K Tx/Rx buffer split */
    if (scp->srev != 1) {
      XE_SELECT_PAGE(2);
      XE_OUTW(XE_RBS, 0x2000);
    }
  
+   /* Enable early transmit mode on Mohawk/Dingo */
+   if (scp->mohawk) {
+     XE_SELECT_PAGE(0x03);
+     XE_OUTW(XE_TPT, scp->tx_thres);
+     XE_SELECT_PAGE(0x01);
+     XE_OUTB(XE_ECR, XE_INB(XE_ECR) | XE_ECR_EARLY_TX);
+   }
+ 
+   /* Put MAC address in first 'individual address' register */
+   XE_SELECT_PAGE(0x50);
+   for (i = 0; i < 6; i++)
+     XE_OUTB(0x08 + i, scp->arpcom.ac_enaddr[scp->mohawk ? 5 - i : i]);
+ 
    /* Set up multicast addresses */
!   xe_set_multicast(scp);
  
!   /* Fix the receive data offset -- reset can leave it off-by-one */
    XE_SELECT_PAGE(0);
    XE_OUTW(XE_DO, 0x2000);
  
!   /* Set interrupt masks */
!   XE_SELECT_PAGE(1);
!   XE_OUTB(XE_IMR0, XE_IMR0_TX_PACKET | XE_IMR0_MAC_INTR | XE_IMR0_RX_PACKET);
  
!   /* Set MAC interrupt masks */
!   XE_SELECT_PAGE(0x40);
!   XE_OUTB(XE_RX0Msk,
! 	  ~(XE_RX0M_RX_OVERRUN | XE_RX0M_CRC_ERROR
! 	    | XE_RX0M_ALIGN_ERROR | XE_RX0M_LONG_PACKET));
!   XE_OUTB(XE_TX0Msk,
! 	  ~(XE_TX0M_SQE_FAIL | XE_TX0M_LATE_COLLISION | XE_TX0M_TX_UNDERRUN
! 	    | XE_TX0M_16_COLLISIONS | XE_TX0M_NO_CARRIER));
! 
!   /* Clear MAC status registers */
!   XE_SELECT_PAGE(0x40);
!   XE_OUTB(XE_RST0, 0x00);
!   XE_OUTB(XE_TXST0, 0x00);
! 
!   /* Enable receiver and put MAC online */
!   XE_SELECT_PAGE(0x40);
!   XE_OUTB(XE_CMD0, XE_CMD0_RX_ENABLE|XE_CMD0_ONLINE);
  
!   /* Set up IMR, enable interrupts */
!   xe_enable_intr(scp);
  
!   /* Start media selection */
!   xe_setmedia(scp);
! 
!   /* Enable output */
!   scp->ifp->if_flags |= IFF_RUNNING;
!   scp->ifp->if_flags &= ~IFF_OACTIVE;
  
    (void)splx(s);
  }
  
  
  /*
!  * Start output on interface.  Should be called at splimp() priority.  Check
!  * that the output is idle (ie, IFF_OACTIVE is not set) before calling this
!  * function.  If media selection is in progress we set IFF_OACTIVE ourselves
!  * and return immediately.
   */
  static void
  xe_start(struct ifnet *ifp) {
    struct xe_softc *scp = ifp->if_softc;
    struct mbuf *mbp;
  
+   if (scp->autoneg_status != XE_AUTONEG_NONE) {
+     ifp->if_flags |= IFF_OACTIVE;
+     return;
+   }
+ 
+ #if XE_DEBUG > 2
+   device_printf(scp->dev, "start");
+ #endif
+ 
    /*
     * Loop while there are packets to be sent, and space to send them.
     */
    while (1) {
!     /* Suck a packet off the send queue */
!     IF_DEQUEUE(&ifp->if_snd, mbp);
  
      if (mbp == NULL) {
        /*
***************
*** 410,416 ****
      }
  
      if (xe_pio_write_packet(scp, mbp) != 0) {
!       IF_PREPEND(&ifp->if_snd, mbp);	/* Push the packet back onto the queue */
        ifp->if_flags |= IFF_OACTIVE;
        return;
      }
--- 454,461 ----
      }
  
      if (xe_pio_write_packet(scp, mbp) != 0) {
!       /* Push the packet back onto the queue */
!       IF_PREPEND(&ifp->if_snd, mbp);
        ifp->if_flags |= IFF_OACTIVE;
        return;
      }
***************
*** 418,424 ****
      /* Tap off here if there is a bpf listener */
      BPF_MTAP(ifp, mbp);
  
!     ifp->if_timer = 5;			/* In case we don't hear from the card again */
      scp->tx_queued++;
  
      m_freem(mbp);
--- 463,470 ----
      /* Tap off here if there is a bpf listener */
      BPF_MTAP(ifp, mbp);
  
!     /* In case we don't hear from the card again... */
!     ifp->if_timer = 5;
      scp->tx_queued++;
  
      m_freem(mbp);
***************
*** 441,455 ****
  
    switch (command) {
  
!    case SIOCSIFFLAGS:
      /*
       * If the interface is marked up and stopped, then start it.  If it is
       * marked down and running, then stop it.
       */
      if (ifp->if_flags & IFF_UP) {
        if (!(ifp->if_flags & IFF_RUNNING)) {
! 	xe_hard_reset(scp);
! 	xe_setmedia(scp);
  	xe_init(scp);
        }
      }
--- 487,503 ----
  
    switch (command) {
  
!   case SIOCSIFFLAGS:
! #if XE_DEBUG > 1
!     device_printf(scp->dev, "ioctl: SIOCSIFFLAGS: 0x%04x\n", ifp->if_flags);
! #endif
      /*
       * If the interface is marked up and stopped, then start it.  If it is
       * marked down and running, then stop it.
       */
      if (ifp->if_flags & IFF_UP) {
        if (!(ifp->if_flags & IFF_RUNNING)) {
! 	xe_reset(scp);
  	xe_init(scp);
        }
      }
***************
*** 457,483 ****
        if (ifp->if_flags & IFF_RUNNING)
  	xe_stop(scp);
      }
  
!    case SIOCADDMULTI:
!    case SIOCDELMULTI:
      /*
!      * Multicast list has (maybe) changed; set the hardware filter
!      * accordingly.  This also serves to deal with promiscuous mode if we have 
!      * a BPF listener active.
       */
!     xe_setmulti(scp);
      error = 0;
      break;
  
!    case SIOCSIFMEDIA:
!    case SIOCGIFMEDIA:
      /*
       * Someone wants to get/set media options.
       */
      error = ifmedia_ioctl(ifp, (struct ifreq *)data, &scp->ifmedia, command);
      break;
  
!    default:
      error = ether_ioctl(ifp, command, data);
    }
  
--- 505,540 ----
        if (ifp->if_flags & IFF_RUNNING)
  	xe_stop(scp);
      }
+     /* FALL THROUGH  (handle changes to PROMISC/ALLMULTI flags) */
  
!   case SIOCADDMULTI:
!   case SIOCDELMULTI:
! #if XE_DEBUG > 1
!     device_printf(scp->dev, "ioctl: SIOC{ADD,DEL}MULTI\n");
! #endif
      /*
!      * Multicast list has (maybe) changed; set the hardware filters
!      * accordingly.
       */
!     xe_set_multicast(scp);
      error = 0;
      break;
  
!   case SIOCSIFMEDIA:
!   case SIOCGIFMEDIA:
! #if XE_DEBUG > 1
!     device_printf(scp->dev, "ioctl: bounce to ifmedia_ioctl\n");
! #endif
      /*
       * Someone wants to get/set media options.
       */
      error = ifmedia_ioctl(ifp, (struct ifreq *)data, &scp->ifmedia, command);
      break;
  
!   default:
! #if XE_DEBUG > 1
!     device_printf(scp->dev, "ioctl: bounce to ether_ioctl\n");
! #endif
      error = ether_ioctl(ifp, command, data);
    }
  
***************
*** 510,757 ****
  {
    struct xe_softc *scp = (struct xe_softc *) xscp;
    struct ifnet *ifp;
!   int result;
!   u_int16_t rx_bytes, rxs, txs;
!   u_int8_t psr, isr, esr, rsr;
  
    ifp = &scp->arpcom.ac_if;
-   rx_bytes = 0;			/* Bytes received on this interrupt */
-   result = 0;			/* Set true if the interrupt is for us */
  
!   if (scp->mohawk) {
!     XE_OUTB(XE_CR, 0);		/* Disable interrupts */
!   }
  
!   psr = XE_INB(XE_PR);		/* Stash the current register page */
  
!   /*
!    * Read ISR to see what caused this interrupt.  Note that this clears the
!    * ISR on CE2 type cards.
!    */
!   if ((isr = XE_INB(XE_ISR)) && isr != 0xff) {
  
!     result = 1;			/* This device did generate an int */
!     esr = XE_INB(XE_ESR);	/* Read the other status registers */
      XE_SELECT_PAGE(0x40);
!     rxs = XE_INB(XE_RST0);
!     XE_OUTB(XE_RST0, ~rxs & 0xff);
!     txs = XE_INB(XE_TXST0);
!     txs |= XE_INB(XE_TXST1) << 8;
      XE_OUTB(XE_TXST0, 0);
      XE_OUTB(XE_TXST1, 0);
      XE_SELECT_PAGE(0);
  
  #if XE_DEBUG > 2
!     printf("xe%d: ISR=%#2.2x ESR=%#2.2x RST=%#2.2x TXST=%#4.4x\n", unit, isr, esr, rxs, txs);
  #endif
  
!     /*
!      * Handle transmit interrupts
!      */
      if (isr & XE_ISR_TX_PACKET) {
!       u_int8_t new_tpr, sent;
!       
!       if ((new_tpr = XE_INB(XE_TPR)) < scp->tx_tpr)	/* Update packet count */
! 	sent = (0xff - scp->tx_tpr) + new_tpr;		/* TPR rolled over */
!       else
! 	sent = new_tpr - scp->tx_tpr;
  
!       if (sent > 0) {				/* Packets sent since last interrupt */
! 	scp->tx_tpr = new_tpr;
  	scp->tx_queued -= sent;
  	ifp->if_opackets += sent;
! 	ifp->if_collisions += scp->tx_collisions;
  
  	/*
! 	 * Collision stats are a PITA.  If multiples frames have been sent, we 
! 	 * distribute any outstanding collision count equally amongst them.
! 	 * However, if we're missing interrupts we're quite likely to also
! 	 * miss some collisions; thus the total count will be off anyway.
! 	 * Likewise, if we miss a frame dropped due to excessive collisions
! 	 * any outstanding collisions count will be held against the next
! 	 * frame to be successfully sent.  Hopefully it averages out in the
! 	 * end!
! 	 * XXX - This will screw up if tx_collisions/sent > 14. FIX IT!
  	 */
! 	switch (scp->tx_collisions) {
! 	 case 0:
  	  break;
! 	 case 1:
  	  scp->mibdata.dot3StatsSingleCollisionFrames++;
  	  scp->mibdata.dot3StatsCollFrequencies[0]++;
  	  break;
! 	 default:
! 	  if (sent == 1) {
! 	    scp->mibdata.dot3StatsMultipleCollisionFrames++;
! 	    scp->mibdata.dot3StatsCollFrequencies[scp->tx_collisions-1]++;
! 	  }
! 	  else {		/* Distribute across multiple frames */
! 	    scp->mibdata.dot3StatsMultipleCollisionFrames += sent;
! 	    scp->mibdata.
! 	      dot3StatsCollFrequencies[scp->tx_collisions/sent] += sent - scp->tx_collisions%sent;
! 	    scp->mibdata.
! 	      dot3StatsCollFrequencies[scp->tx_collisions/sent + 1] += scp->tx_collisions%sent;
! 	  }
  	}
- 	scp->tx_collisions = 0;
        }
        ifp->if_timer = 0;
        ifp->if_flags &= ~IFF_OACTIVE;
      }
-     if (txs & 0x0002) {		/* Excessive collisions (packet dropped) */
-       ifp->if_collisions += 16;
-       ifp->if_oerrors++;
-       scp->tx_collisions = 0;
-       scp->mibdata.dot3StatsExcessiveCollisions++;
-       scp->mibdata.dot3StatsMultipleCollisionFrames++;
-       scp->mibdata.dot3StatsCollFrequencies[15]++;
-       XE_OUTB(XE_CR, XE_CR_RESTART_TX);
-     }
-     if (txs & 0x0040)		/* Transmit aborted -- probably collisions */
-       scp->tx_collisions++;
  
  
!     /*
!      * Handle receive interrupts 
!      */
      while ((esr = XE_INB(XE_ESR)) & XE_ESR_FULL_PACKET_RX) {
  
!       if ((rsr = XE_INB(XE_RSR)) & XE_RSR_RX_OK) {
  	struct ether_header *ehp;
  	struct mbuf *mbp;
  	u_int16_t len;
  
! 	len = XE_INW(XE_RBC);
  
! 	if (len == 0)
  	  continue;
  
- #if 0
  	/*
! 	 * Limit the amount of time we spend in this loop, dropping packets if 
! 	 * necessary.  The Linux code does this with considerably more
! 	 * finesse, adjusting the threshold dynamically.
  	 */
! 	if ((rx_bytes += len) > 22000) {
  	  ifp->if_iqdrops++;
- 	  scp->mibData.dot3StatsMissedFrames++;
- 	  XE_OUTW(XE_DO, 0x8000);
  	  continue;
  	}
- #endif
  
! 	if (len & 0x01)
! 	  len++;
! 
! 	MGETHDR(mbp, M_DONTWAIT, MT_DATA);	/* Allocate a header mbuf */
! 	if (mbp != NULL) {
! 	  mbp->m_pkthdr.rcvif = ifp;
! 	  mbp->m_pkthdr.len = mbp->m_len = len;
! 
! 	  /*
! 	   * If the mbuf header isn't big enough for the packet, attach an
! 	   * mbuf cluster to hold it.  The +2 is to allow for the nasty little 
! 	   * alignment hack below.
! 	   */
! 	  if (len + 2 > MHLEN) {
! 	    MCLGET(mbp, M_DONTWAIT);
! 	    if ((mbp->m_flags & M_EXT) == 0) {
! 	      m_freem(mbp);
! 	      mbp = NULL;
! 	    }
  	  }
  	}
  
! 	if (mbp != NULL) {
! 	  /*
! 	   * The Ethernet header is 14 bytes long; thus the actual packet data 
! 	   * won't be 32-bit aligned when it's dumped into the mbuf.  We
! 	   * offset everything by 2 bytes to fix this.  Apparently the
! 	   * alignment is important for NFS, damn its eyes.
! 	   */
! 	  mbp->m_data += 2;
! 	  ehp = mtod(mbp, struct ether_header *);
  
! 	  /*
! 	   * Now get the packet, including the Ethernet header and trailer (?)
! 	   * We use programmed I/O, because we don't know how to do shared
! 	   * memory with these cards.  So yes, it's real slow, and heavy on
! 	   * the interrupts (CPU on my P150 maxed out at ~950KBps incoming).
! 	   */
! 	  if (scp->srev == 0) {		/* Workaround a bug in old cards */
! 	    u_short rhs;
  
! 	    XE_SELECT_PAGE(5);
! 	    rhs = XE_INW(XE_RHSA);
! 	    XE_SELECT_PAGE(0);
! 
! 	    rhs += 3;			 /* Skip control info */
! 
! 	    if (rhs >= 0x8000)
! 	      rhs = 0;
! 
! 	    if (rhs + len > 0x8000) {
! 	      int i;
! 
! 	      /*
! 	       * XXX - This i-- seems very wrong, but it's what the Linux guys 
! 	       * XXX - do.  Need someone with an old CE2 to test this for me.
! 	       * XXX - 99/3/28: Changed the first i-- to an i++, maybe that'll
! 	       * XXX - fix it?  It seems as though the previous version would
! 	       * XXX - have caused an infinite loop (what, another one?).
! 	       */
! 	      for (i = 0; i < len; i++, rhs++) {
! 		((char *)ehp)[i] = XE_INB(XE_EDP);
! 		if (rhs == 0x8000) {
! 		  rhs = 0;
! 		  i--;
! 		}
  	      }
  	    }
- 	    else
- 	      bus_space_read_multi_2(scp->bst, scp->bsh, XE_EDP, 
- 	       (u_int16_t *) ehp, len >> 1);
  	  }
  	  else
  	    bus_space_read_multi_2(scp->bst, scp->bsh, XE_EDP, 
! 	     (u_int16_t *) ehp, len >> 1);
! 
! 	  /* Deliver packet to upper layers */
! 	  if (mbp != NULL) {
! 	    mbp->m_flags |= M_HASFCS;		/* FCS is included in our
! 						 * packet */
! 	    mbp->m_pkthdr.len = mbp->m_len = len;
! 	    (*ifp->if_input)(ifp, mbp);		/* Send the packet on its way */
! 	    ifp->if_ipackets++;			/* Success! */
! 	  }
! 	  XE_OUTW(XE_DO, 0x8000);		/* skip_rx_packet command */
  	}
        }
!       else if (rsr & XE_RSR_LONG_PACKET) {	/* Packet length >1518 bytes */
! 	scp->mibdata.dot3StatsFrameTooLongs++;
! 	ifp->if_ierrors++;
!       }
!       else if (rsr & XE_RSR_CRC_ERROR) {	/* Bad checksum on packet */
! 	scp->mibdata.dot3StatsFCSErrors++;
! 	ifp->if_ierrors++;
!       }
!       else if (rsr & XE_RSR_ALIGN_ERROR) {	/* Packet alignment error */
  	scp->mibdata.dot3StatsAlignmentErrors++;
  	ifp->if_ierrors++;
        }
      }
!     if (rxs & 0x10) {				/* Receiver overrun */
!       scp->mibdata.dot3StatsInternalMacReceiveErrors++;
        ifp->if_ierrors++;
        XE_OUTB(XE_CR, XE_CR_CLEAR_OVERRUN);
      }
    }
  
!   XE_SELECT_PAGE(psr);				/* Restore saved page */
!   XE_OUTB(XE_CR, XE_CR_ENABLE_INTR);		/* Re-enable interrupts */
  
!   /* Could force an int here, instead of dropping packets? */
!   /* XE_OUTB(XE_CR, XE_CR_ENABLE_INTR|XE_CE_FORCE_INTR); */
  
    return;
  }
--- 567,823 ----
  {
    struct xe_softc *scp = (struct xe_softc *) xscp;
    struct ifnet *ifp;
!   u_int8_t psr, isr, esr, rsr, rst0, txst0, txst1, coll;
  
    ifp = &scp->arpcom.ac_if;
  
!   /* Disable interrupts */
!   XE_OUTB(XE_CR, 0);
  
!   /* Cache current register page */
!   psr = XE_INB(XE_PR);
  
!   /* Read ISR to see what caused this interrupt */
!   if ((isr = XE_INB(XE_ISR)) != 0) {
  
!     /* Read other status registers */
      XE_SELECT_PAGE(0x40);
!     rst0 = XE_INB(XE_RST0);
!     XE_OUTB(XE_RST0, 0);
!     txst0 = XE_INB(XE_TXST0);
!     txst1 = XE_INB(XE_TXST1);
!     coll = txst1 & XE_TXST1_RETRY_COUNT;
      XE_OUTB(XE_TXST0, 0);
      XE_OUTB(XE_TXST1, 0);
      XE_SELECT_PAGE(0);
  
  #if XE_DEBUG > 2
!     device_printf(scp->dev, "intr: ISR=0x%02x, RST=0x%02x, TXT=0x%02x%02x, COLL=0x%01x\n", isr, rst0, txst1, txst0, coll);
  #endif
  
!     /* Handle transmitted packet(s) */
      if (isr & XE_ISR_TX_PACKET) {
!       u_int8_t tpr, sent;
  
!       /* Update packet count, accounting for rollover */
!       tpr = XE_INB(XE_TPR);
!       sent = -scp->tx_tpr + tpr;
! 
!       /* Update statistics if we actually sent anything */
!       if (sent > 0) {
! 	scp->tx_tpr = tpr;
  	scp->tx_queued -= sent;
  	ifp->if_opackets += sent;
! 	ifp->if_collisions += coll;
  
  	/*
! 	 * According to the Xircom manual, Dingo will sometimes manage to
! 	 * transmit a packet with triggering an interrupt.  If this happens,
! 	 * we have sent > 1 and the collision count only reflects collisions
! 	 * on the last packet sent (the one that triggered the interrupt).
! 	 * Collision stats might therefore be a bit low, but there doesn't
! 	 * seem to be anything we can do about that.
  	 */
! 
! 	switch (coll) {
! 	case 0:
  	  break;
! 	case 1:
  	  scp->mibdata.dot3StatsSingleCollisionFrames++;
  	  scp->mibdata.dot3StatsCollFrequencies[0]++;
  	  break;
! 	default:
! 	  scp->mibdata.dot3StatsMultipleCollisionFrames++;
! 	  scp->mibdata.dot3StatsCollFrequencies[coll-1]++;
  	}
        }
        ifp->if_timer = 0;
        ifp->if_flags &= ~IFF_OACTIVE;
      }
  
+     /* Handle most MAC interrupts */
+     if (isr & XE_ISR_MAC_INTR) {
  
! #if 0
!       /* Carrier sense lost -- only in 10Mbit HDX mode */
!       if (txst0 & XE_TXST0_NO_CARRIER || !(txst1 & XE_TXST1_LINK_STATUS)) {
! 	/* XXX - Need to update media status here */
! 	device_printf(scp->dev, "no carrier\n");
! 	ifp->if_oerrors++;
! 	scp->mibdata.dot3StatsCarrierSenseErrors++;
!       }
! #endif
!       /* Excessive collisions -- try sending again */
!       if (txst0 & XE_TXST0_16_COLLISIONS) {
! 	ifp->if_collisions += 16;
! 	ifp->if_oerrors++;
! 	scp->mibdata.dot3StatsExcessiveCollisions++;
! 	scp->mibdata.dot3StatsMultipleCollisionFrames++;
! 	scp->mibdata.dot3StatsCollFrequencies[15]++;
! 	XE_OUTB(XE_CR, XE_CR_RESTART_TX);
!       }
!       /* Transmit underrun -- increase early transmit threshold */
!       if (txst0 & XE_TXST0_TX_UNDERRUN) {
! 	device_printf(scp->dev, "transmit underrun");
! 	if (scp->tx_thres < ETHER_MAX_LEN) {
! 	  if ((scp->tx_thres += 64) > ETHER_MAX_LEN)
! 	    scp->tx_thres = ETHER_MAX_LEN;
! 	  printf(": increasing transmit threshold to %u", scp->tx_thres);
! 	  XE_SELECT_PAGE(0x3);
! 	  XE_OUTW(XE_TPT, scp->tx_thres);
! 	  XE_SELECT_PAGE(0x0);
! 	}
! 	printf("\n");
! 	ifp->if_oerrors++;
! 	scp->mibdata.dot3StatsInternalMacTransmitErrors++;
!       }
!       /* Late collision -- just complain about it */
!       if (txst0 & XE_TXST0_LATE_COLLISION) {
! 	device_printf(scp->dev, "late collision\n");
! 	ifp->if_oerrors++;
! 	scp->mibdata.dot3StatsLateCollisions++;
!       }
!       /* SQE test failure -- just complain about it */
!       if (txst0 & XE_TXST0_SQE_FAIL) {
! 	device_printf(scp->dev, "SQE test failure\n");
! 	ifp->if_oerrors++;
! 	scp->mibdata.dot3StatsSQETestErrors++;
!       }
!       /* Packet too long -- what happens to these */
!       if (rst0 & XE_RST0_LONG_PACKET) {
! 	device_printf(scp->dev, "received giant packet\n");
! 	ifp->if_ierrors++;
! 	scp->mibdata.dot3StatsFrameTooLongs++;
!       }
!       /* CRC error -- packet dropped */
!       if (rst0 & XE_RST0_CRC_ERROR) {
! 	device_printf(scp->dev, "CRC error\n");
! 	ifp->if_ierrors++;
! 	scp->mibdata.dot3StatsFCSErrors++;
!       }
!     }
! 
!     /* Handle received packet(s) */
      while ((esr = XE_INB(XE_ESR)) & XE_ESR_FULL_PACKET_RX) {
+       rsr = XE_INB(XE_RSR);
  
! #if XE_DEBUG > 2
!     device_printf(scp->dev, "intr: ESR=0x%02x, RSR=0x%02x\n", esr, rsr,);
! #endif
! 
!       /* Make sure packet is a good one */
!       if (rsr & XE_RSR_RX_OK) {
  	struct ether_header *ehp;
  	struct mbuf *mbp;
  	u_int16_t len;
  
! 	len = XE_INW(XE_RBC) - ETHER_CRC_LEN;
  
! 	if (len == 0) {
! 	  ifp->if_iqdrops++;
  	  continue;
+ 	}
  
  	/*
! 	 * Allocate mbuf to hold received packet.  If the mbuf header isn't
! 	 * big enough, we attach an mbuf cluster to hold the packet.  Note the
! 	 * +=2 to align the packet data on a 32-bit boundary, and the +3 to
! 	 * allow for the possibility of reading one more byte than the actual
! 	 * packet length (we always read 16-bit words).
! 	 * XXX - Surely there's a better way to do this alignment?
  	 */
! 	MGETHDR(mbp, M_DONTWAIT, MT_DATA);
! 	if (mbp == NULL) {
  	  ifp->if_iqdrops++;
  	  continue;
  	}
  
! 	if (len + 3 > MHLEN) {
! 	  MCLGET(mbp, M_DONTWAIT);
! 	  if ((mbp->m_flags & M_EXT) == 0) {
! 	    m_freem(mbp);
! 	    ifp->if_iqdrops++;
! 	    continue;
  	  }
  	}
  
! 	mbp->m_data += 2;
! 	ehp = mtod(mbp, struct ether_header *);
  
! 	/*
! 	 * Now get the packet in PIO mode, including the Ethernet header but
! 	 * omitting the trailing CRC.
! 	 */
! 
! 	/*
! 	 * Work around a bug in CE2 cards.  There seems to be a problem with
! 	 * duplicated and extraneous bytes in the receive buffer, but without
! 	 * any real documentation for the CE2 it's hard to tell for sure.
! 	 * XXX - Needs testing on CE2 hardware
! 	 */
! 	if (scp->srev == 0) {
! 	  u_short rhs;
  
! 	  XE_SELECT_PAGE(5);
! 	  rhs = XE_INW(XE_RHSA);
! 	  XE_SELECT_PAGE(0);
! 
! 	  rhs += 3;			 /* Skip control info */
! 
! 	  if (rhs >= 0x8000)
! 	    rhs = 0;
! 
! 	  if (rhs + len > 0x8000) {
! 	    int i;
! 
! 	    for (i = 0; i < len; i++, rhs++) {
! 	      ((char *)ehp)[i] = XE_INB(XE_EDP);
! 	      if (rhs == 0x8000) {
! 		rhs = 0;
! 		i--;
  	      }
  	    }
  	  }
  	  else
  	    bus_space_read_multi_2(scp->bst, scp->bsh, XE_EDP, 
! 				   (u_int16_t *) ehp, (len + 1) >> 1);
  	}
+ 	else
+ 	  bus_space_read_multi_2(scp->bst, scp->bsh, XE_EDP, 
+ 				 (u_int16_t *) ehp, (len + 1) >> 1);
+ 
+ 	/* Deliver packet to upper layers */
+ 	mbp->m_pkthdr.rcvif = ifp;
+ 	mbp->m_pkthdr.len = mbp->m_len = len;
+ 	(*ifp->if_input)(ifp, mbp);
+ 	ifp->if_ipackets++;
        }
! 
!       /* Packet alignment error -- drop packet */
!       else if (rsr & XE_RSR_ALIGN_ERROR) {
! 	device_printf(scp->dev, "alignment error\n");
  	scp->mibdata.dot3StatsAlignmentErrors++;
  	ifp->if_ierrors++;
        }
+ 
+       /* Skip to next packet, if there is one */
+       XE_OUTW(XE_DO, 0x8000);
      }
! 
!     /* Clear receiver overruns now we have some free buffer space */
!     if (rst0 & XE_RST0_RX_OVERRUN) {
!       device_printf(scp->dev, "receive overrun\n");
        ifp->if_ierrors++;
+       scp->mibdata.dot3StatsInternalMacReceiveErrors++;
        XE_OUTB(XE_CR, XE_CR_CLEAR_OVERRUN);
      }
    }
  
!   /* Restore saved page */
!   XE_SELECT_PAGE(psr);
  
!   /* Re-enable interrupts */
!   XE_OUTB(XE_CR, XE_CR_ENABLE_INTR);
  
    return;
  }
***************
*** 767,778 ****
  xe_watchdog(struct ifnet *ifp) {
    struct xe_softc *scp = ifp->if_softc;
  
!   device_printf(scp->dev, "watchdog timeout; resetting card\n");
    scp->tx_timeouts++;
    ifp->if_oerrors += scp->tx_queued;
    xe_stop(scp);
!   xe_hard_reset(scp);
!   xe_setmedia(scp);
    xe_init(scp);
  }
  
--- 833,843 ----
  xe_watchdog(struct ifnet *ifp) {
    struct xe_softc *scp = ifp->if_softc;
  
!   device_printf(scp->dev, "watchdog timeout: resetting card\n");
    scp->tx_timeouts++;
    ifp->if_oerrors += scp->tx_queued;
    xe_stop(scp);
!   xe_reset(scp);
    xe_init(scp);
  }
  
***************
*** 784,790 ****
  xe_media_change(struct ifnet *ifp) {
    struct xe_softc *scp = ifp->if_softc;
  
! #ifdef XE_DEBUG
    if_printf(ifp, "media_change\n");
  #endif
  
--- 849,855 ----
  xe_media_change(struct ifnet *ifp) {
    struct xe_softc *scp = ifp->if_softc;
  
! #if XE_DEBUG > 1
    if_printf(ifp, "media_change\n");
  #endif
  
***************
*** 810,819 ****
  static void
  xe_media_status(struct ifnet *ifp, struct ifmediareq *mrp) {
  
! #ifdef XE_DEBUG
    if_printf(ifp, "media_status\n");
  #endif
  
    mrp->ifm_active = ((struct xe_softc *)ifp->if_softc)->media;
  
    return;
--- 875,886 ----
  static void
  xe_media_status(struct ifnet *ifp, struct ifmediareq *mrp) {
  
! #if XE_DEBUG > 1
    if_printf(ifp, "media_status\n");
  #endif
  
+   /* XXX - This is clearly wrong.  Will fix once I have CE2 working */
+   mrp->ifm_status = IFM_AVALID | IFM_ACTIVE;
    mrp->ifm_active = ((struct xe_softc *)ifp->if_softc)->media;
  
    return;
***************
*** 827,833 ****
    struct xe_softc *scp = xscp;
    u_int16_t bmcr, bmsr, anar, lpar;
  
! #ifdef XE_DEBUG
    device_printf(scp->dev, "setmedia\n");
  #endif
  
--- 894,900 ----
    struct xe_softc *scp = xscp;
    u_int16_t bmcr, bmsr, anar, lpar;
  
! #if XE_DEBUG > 1
    device_printf(scp->dev, "setmedia\n");
  #endif
  
***************
*** 873,889 ****
       */
      switch (scp->autoneg_status) {
  
!      case XE_AUTONEG_NONE:
  #if XE_DEBUG > 1
        device_printf(scp->dev, "Waiting for idle transmitter\n");
  #endif
        scp->arpcom.ac_if.if_flags |= IFF_OACTIVE;
        scp->autoneg_status = XE_AUTONEG_WAITING;
!       scp->chand = timeout(xe_setmedia, scp, hz * 2);
!       return;
  
!      case XE_AUTONEG_WAITING:
!       xe_soft_reset(scp);
        if (scp->phy_ok) {
  #if XE_DEBUG > 1
  	device_printf(scp->dev, "Starting autonegotiation\n");
--- 940,958 ----
       */
      switch (scp->autoneg_status) {
  
!     case XE_AUTONEG_NONE:
  #if XE_DEBUG > 1
        device_printf(scp->dev, "Waiting for idle transmitter\n");
  #endif
        scp->arpcom.ac_if.if_flags |= IFF_OACTIVE;
        scp->autoneg_status = XE_AUTONEG_WAITING;
!       /* FALL THROUGH */
  
!     case XE_AUTONEG_WAITING:
!       if (scp->tx_queued != 0) {
! 	scp->chand = timeout(xe_setmedia, scp, hz/2);
! 	return;
!       }
        if (scp->phy_ok) {
  #if XE_DEBUG > 1
  	device_printf(scp->dev, "Starting autonegotiation\n");
***************
*** 898,904 ****
  	bmcr |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR;
  	xe_phy_writereg(scp, PHY_BMCR, bmcr);
  	scp->autoneg_status = XE_AUTONEG_STARTED;
! 	scp->chand = timeout(xe_setmedia, scp, hz * 7/2);
  	return;
        }
        else {
--- 967,973 ----
  	bmcr |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR;
  	xe_phy_writereg(scp, PHY_BMCR, bmcr);
  	scp->autoneg_status = XE_AUTONEG_STARTED;
!  	scp->chand = timeout(xe_setmedia, scp, hz * 7/2);
  	return;
        }
        else {
***************
*** 953,959 ****
  	device_printf(scp->dev, "Autonegotiation failed; trying 100baseTX\n");
  #endif
  	XE_MII_DUMP(scp);
- 	xe_soft_reset(scp);
  	if (scp->phy_ok) {
  	  xe_phy_writereg(scp, PHY_BMCR, PHY_BMCR_SPEEDSEL);
  	  scp->autoneg_status = XE_AUTONEG_100TX;
--- 1022,1027 ----
***************
*** 1028,1034 ****
       * no PHY, we fall back to 10baseT operation).
       */
     case IFM_100_TX:	/* Force 100baseTX */
-     xe_soft_reset(scp);
      if (scp->phy_ok) {
  #if XE_DEBUG > 1
        device_printf(scp->dev, "Selecting 100baseTX\n");
--- 1096,1101 ----
***************
*** 1044,1050 ****
      /* FALLTHROUGH */
  
     case IFM_10_T:	/* Force 10baseT */
-     xe_soft_reset(scp);
  #if XE_DEBUG > 1
      device_printf(scp->dev, "Selecting 10baseT\n");
  #endif
--- 1111,1116 ----
***************
*** 1059,1065 ****
      break;
  
     case IFM_10_2:
-     xe_soft_reset(scp);
  #if XE_DEBUG > 1
      device_printf(scp->dev, "Selecting 10base2\n");
  #endif
--- 1125,1130 ----
***************
*** 1092,1099 ****
    }
  
    /* Restart output? */
    scp->ifp->if_flags &= ~IFF_OACTIVE;
!   xe_init(scp);
  }
  
  
--- 1157,1165 ----
    }
  
    /* Restart output? */
+   xe_enable_intr(scp);
    scp->ifp->if_flags &= ~IFF_OACTIVE;
!   xe_start(scp->ifp);
  }
  
  
***************
*** 1101,1198 ****
   * Hard reset (power cycle) the card.
   */
  static void
! xe_hard_reset(struct xe_softc *scp) {
    int s;
  
! #ifdef XE_DEBUG
!   device_printf(scp->dev, "hard_reset\n");
  #endif
  
    s = splimp();
  
!   /*
!    * Power cycle the card.
!    */
    XE_SELECT_PAGE(4);
!   XE_OUTB(XE_GPR1, 0);		/* Power off */
    DELAY(40000);
  
    if (scp->mohawk)
!     XE_OUTB(XE_GPR1, 1);	/* And back on again */
    else
!     XE_OUTB(XE_GPR1, 5);	/* Also set AIC bit, whatever that is */
!   DELAY(40000);
!   XE_SELECT_PAGE(0);
! 
!   (void)splx(s);
! }
! 
  
- /*
-  * Soft reset the card.  Also makes sure that the ML6692 and 10Mbit controller 
-  * are powered up, sets the silicon revision number in softc, disables
-  * interrupts and checks for the prescence of a 100Mbit PHY.  This should
-  * leave us in a position where we can access the PHY and do media
-  * selection. The function imposes a 0.5s delay while the hardware powers up.
-  */
- static void
- xe_soft_reset(struct xe_softc *scp) {
-   int s;
- 
- #ifdef XE_DEBUG
-   device_printf(scp->dev, "soft_reset\n");
- #endif
- 
-   s = splimp();
- 
-   /*
-    * Reset the card, (again).
-    */
-   XE_SELECT_PAGE(0);
-   XE_OUTB(XE_CR, XE_CR_SOFT_RESET);
-   DELAY(40000);
-   XE_OUTB(XE_CR, 0);
    DELAY(40000);
- 
-   if (scp->mohawk) {
-     /*
-      * set GP1 and GP2 as outputs (bits 2 & 3)
-      * set GP1 low to power on the ML6692 (bit 0)
-      * set GP2 high to power on the 10Mhz chip (bit 1)
-      */
-     XE_SELECT_PAGE(4);
-     XE_OUTB(XE_GPR0, 0x0e);
-   }
- 
-   /*
-    * Wait for everything to wake up.
-    */
-   DELAY(500000);
- 
-   /*
-    * Get silicon revision number.
-    */
-   XE_SELECT_PAGE(4);
-   if (scp->mohawk)
-     scp->srev = (XE_INB(XE_BOV) & 0x70) >> 4;
-   else
-     scp->srev = (XE_INB(XE_BOV) & 0x30) >> 4;
- #ifdef XE_DEBUG
-   device_printf(scp->dev, "silicon revision = %d\n", scp->srev);
- #endif
-   
-   /*
-    * Shut off interrupts.
-    */
-   xe_disable_intr(scp);
- 
-   /*
-    * Check for PHY.
-    */
-   if (scp->mohawk) {
-     scp->phy_ok = xe_mii_init(scp);
-   }
- 
    XE_SELECT_PAGE(0);
  
    (void)splx(s);
--- 1167,1193 ----
   * Hard reset (power cycle) the card.
   */
  static void
! xe_reset(struct xe_softc *scp) {
    int s;
  
! #if XE_DEBUG > 1
!   device_printf(scp->dev, "reset\n");
  #endif
  
    s = splimp();
  
!   /* Power down */
    XE_SELECT_PAGE(4);
!   XE_OUTB(XE_GPR1, 0);
    DELAY(40000);
  
+   /* Power up again */
    if (scp->mohawk)
!     XE_OUTB(XE_GPR1, XE_GPR1_POWER_DOWN);
    else
!     XE_OUTB(XE_GPR1, XE_GPR1_POWER_DOWN|XE_GPR1_AIC);
  
    DELAY(40000);
    XE_SELECT_PAGE(0);
  
    (void)splx(s);
***************
*** 1208,1214 ****
  xe_stop(struct xe_softc *scp) {
    int s;
  
! #ifdef XE_DEBUG
    device_printf(scp->dev, "stop\n");
  #endif
  
--- 1203,1209 ----
  xe_stop(struct xe_softc *scp) {
    int s;
  
! #if XE_DEBUG > 1
    device_printf(scp->dev, "stop\n");
  #endif
  
***************
*** 1225,1230 ****
--- 1220,1234 ----
    XE_SELECT_PAGE(4);
    XE_OUTB(XE_GPR1, 0);
    XE_SELECT_PAGE(0);
+   if (scp->mohawk) {
+     /*
+      * set GP1 and GP2 as outputs (bits 2 & 3)
+      * set GP1 high to power on the ML6692 (bit 0)
+      * set GP2 low to power on the 10Mhz chip (bit 1)
+      */
+     XE_SELECT_PAGE(4);
+     XE_OUTB(XE_GPR0, XE_GPR0_GP2_SELECT|XE_GPR0_GP1_SELECT|XE_GPR0_GP1_OUT);
+   }
  
    /*
     * ~IFF_RUNNING == interface down.
***************
*** 1238,1256 ****
  
  
  /*
!  * Enable Ethernet interrupts from the card.
   */
  static void
  xe_enable_intr(struct xe_softc *scp) {
! #ifdef XE_DEBUG
    device_printf(scp->dev, "enable_intr\n");
  #endif
  
-   XE_SELECT_PAGE(1);
-   XE_OUTB(XE_IMR0, 0xff);		/* Unmask everything */
-   XE_OUTB(XE_IMR1, 0x01);		/* Unmask TX underrun detection */
-   DELAY(1);
- 
    XE_SELECT_PAGE(0);
    XE_OUTB(XE_CR, XE_CR_ENABLE_INTR);	/* Enable interrupts */
    if (scp->modem && !scp->dingo) {	/* This bit is just magic */
--- 1242,1256 ----
  
  
  /*
!  * Enable interrupts from the card.
   */
  static void
  xe_enable_intr(struct xe_softc *scp) {
! 
! #if XE_DEBUG > 1
    device_printf(scp->dev, "enable_intr\n");
  #endif
  
    XE_SELECT_PAGE(0);
    XE_OUTB(XE_CR, XE_CR_ENABLE_INTR);	/* Enable interrupts */
    if (scp->modem && !scp->dingo) {	/* This bit is just magic */
***************
*** 1262,1393 ****
  
  
  /*
!  * Disable all Ethernet interrupts from the card.
   */
  static void
  xe_disable_intr(struct xe_softc *scp) {
! #ifdef XE_DEBUG
    device_printf(scp->dev, "disable_intr\n");
  #endif
  
    XE_SELECT_PAGE(0);
    XE_OUTB(XE_CR, 0);			/* Disable interrupts */
!   if (scp->modem && !scp->dingo) {	/* More magic (does this work?) */
      XE_OUTB(0x10, 0x10);		/* Mask the master int enable bit */
    }
- 
-   XE_SELECT_PAGE(1);
-   XE_OUTB(XE_IMR0, 0);			/* Forbid all interrupts */
-   XE_OUTB(XE_IMR1, 0);
-   XE_SELECT_PAGE(0);
  }
  
  
  /*
!  * Set up multicast filter and promiscuous mode
   */
  static void
! xe_setmulti(struct xe_softc *scp) {
    struct ifnet *ifp;
    struct ifmultiaddr *maddr;
!   int count;
  
    ifp = &scp->arpcom.ac_if;
!   maddr = TAILQ_FIRST(&ifp->if_multiaddrs);
  
!   /* Get length of multicast list */
!   for (count = 0; maddr != NULL; maddr = TAILQ_NEXT(maddr, ifma_link), count++);
  
!   if ((ifp->if_flags & IFF_PROMISC) || (ifp->if_flags & IFF_ALLMULTI) || (count > 9)) {
!     /*
!      * Go into promiscuous mode if either of the PROMISC or ALLMULTI flags are
!      * set, or if we have been asked to deal with more than 9 multicast
!      * addresses.  To do this: set MPE and PME in SWC1
!      */
!     XE_SELECT_PAGE(0x42);
!     XE_OUTB(XE_SWC1, 0x06);
    }
!   else if ((ifp->if_flags & IFF_MULTICAST) && (count > 0)) {
!     /*
!      * Program the filters for up to 9 addresses
!      */
      XE_SELECT_PAGE(0x42);
!     XE_OUTB(XE_SWC1, 0x01);
!     XE_SELECT_PAGE(0x40);
!     XE_OUTB(XE_CMD0, XE_CMD0_OFFLINE);
!     /*xe_reg_dump(scp);*/
!     xe_setaddrs(scp);
!     /*xe_reg_dump(scp);*/
!     XE_SELECT_PAGE(0x40);
!     XE_OUTB(XE_CMD0, XE_CMD0_RX_ENABLE|XE_CMD0_ONLINE);
    }
!   else {
!     /*
!      * No multicast operation (default)
!      */
      XE_SELECT_PAGE(0x42);
!     XE_OUTB(XE_SWC1, 0);
    }
    XE_SELECT_PAGE(0);
  }
  
  
  /*
!  * Set up all on-chip addresses (for multicast).  AFAICS, there are 10
!  * of these things; the first is our MAC address, the other 9 are mcast
!  * addresses, padded with the MAC address if there aren't enough.
!  * XXX - This doesn't work right, but I'm not sure why yet.  We seem to be
!  * XXX - doing much the same as the Linux code, which is weird enough that
!  * XXX - it's probably right (despite my earlier comments to the contrary).
   */
  static void
! xe_setaddrs(struct xe_softc *scp) {
!   struct ifmultiaddr *maddr;
!   u_int8_t *addr;
!   u_int8_t page, slot, byte, i;
! 
!   maddr = TAILQ_FIRST(&scp->arpcom.ac_if.if_multiaddrs);
  
!   XE_SELECT_PAGE(page = 0x50);
  
!   for (slot = 0, byte = 8; slot < 10; slot++) {
  
!     if (slot == 0)
!       addr = (u_int8_t *)(&scp->arpcom.ac_enaddr);
!     else {
!       while (maddr != NULL && maddr->ifma_addr->sa_family != AF_LINK)
! 	maddr = TAILQ_NEXT(maddr, ifma_link);
!       if (maddr != NULL)
! 	addr = LLADDR((struct sockaddr_dl *)maddr->ifma_addr);
!       else
! 	addr = (u_int8_t *)(&scp->arpcom.ac_enaddr);
      }
! 
!     for (i = 0; i < 6; i++, byte++) {
! #if XE_DEBUG > 2
!       if (i)
! 	printf(":%x", addr[i]);
!       else
! 	device_printf(scp->dev, "individual addresses %d: %x", slot, addr[0]);
  #endif
  
-       if (byte > 15) {
- 	page++;
- 	byte = 8;
- 	XE_SELECT_PAGE(page);
-       }
  
!       if (scp->mohawk)
! 	XE_OUTB(byte, addr[5 - i]);
        else
! 	XE_OUTB(byte, addr[i]);
      }
! #if XE_DEBUG > 2
!     printf("\n");
  #endif
    }
  
!   XE_SELECT_PAGE(0);
  }
  
  
--- 1262,1497 ----
  
  
  /*
!  * Disable interrupts from the card.
   */
  static void
  xe_disable_intr(struct xe_softc *scp) {
! 
! #if XE_DEBUG > 1
    device_printf(scp->dev, "disable_intr\n");
  #endif
  
    XE_SELECT_PAGE(0);
    XE_OUTB(XE_CR, 0);			/* Disable interrupts */
!   if (scp->modem && !scp->dingo) {	/* More magic */
      XE_OUTB(0x10, 0x10);		/* Mask the master int enable bit */
    }
  }
  
  
  /*
!  * Set up multicast filter and promiscuous modes.
   */
  static void
! xe_set_multicast(struct xe_softc *scp) {
    struct ifnet *ifp;
    struct ifmultiaddr *maddr;
!   unsigned count, i;
! 
! #if XE_DEBUG > 1
!   device_printf(scp->dev, "set_multicast\n");
! #endif
  
    ifp = &scp->arpcom.ac_if;
!   XE_SELECT_PAGE(0x42);
  
!   /* Handle PROMISC flag */
!   if (ifp->if_flags & IFF_PROMISC) {
!     XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) | XE_SWC1_PROMISCUOUS);
!     return;
!   }
!   else
!     XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) & ~XE_SWC1_PROMISCUOUS);
  
!   /* Handle ALLMULTI flag */
!   if (ifp->if_flags & IFF_ALLMULTI) {
!     XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) | XE_SWC1_ALLMULTI);
!     return;
    }
!   else
!     XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) & ~XE_SWC1_ALLMULTI);
! 
!   /* Iterate over multicast address list */
!   count = 0;
! #if __FreeBSD_version < 500000
!   LIST_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
! #else
!   TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
! #endif
!     if (maddr->ifma_addr->sa_family != AF_LINK)
!       continue;
! 
!     count++;
! 
!     if (count < 10)
!       /* First 9 use Individual Addresses for exact matching */
!       xe_set_addr(scp, LLADDR((struct sockaddr_dl *)maddr->ifma_addr), count);
!     else
!       if (scp->mohawk)
! 	/* Use hash filter on Mohawk and Dingo */
! 	xe_set_hash(scp, LLADDR((struct sockaddr_dl *)maddr->ifma_addr));
!       else
! 	/* Nowhere else to put them on CE2 */
! 	break;
!   }
! 
! #if XE_DEBUG > 1
!   device_printf(scp->dev, "set_multicast: count = %u\n", count);
! #endif
! 
!   /* Now do some cleanup and enable multicast handling as needed */
!   if (count == 0) {
!     /* Disable all multicast handling */
      XE_SELECT_PAGE(0x42);
!     XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) & ~(XE_SWC1_IA_ENABLE|XE_SWC1_ALLMULTI));
!     if (scp->mohawk) {
!       XE_SELECT_PAGE(0x02);
!       XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~XE_MSR_HASH_TABLE);
!     }
    }
!   else if (count < 10) {
!     /* Full in any unused Individual Addresses with our MAC address */
!     for (i = count + 1; i < 10; i++)
!       xe_set_addr(scp, (u_int8_t *)(&scp->arpcom.ac_enaddr), i);
!     /* Enable Individual Address matching only */
      XE_SELECT_PAGE(0x42);
!     XE_OUTB(XE_SWC1, (XE_INB(XE_SWC1) & ~XE_SWC1_ALLMULTI) | XE_SWC1_IA_ENABLE);
!     if (scp->mohawk) {
!       XE_SELECT_PAGE(0x02);
!       XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~XE_MSR_HASH_TABLE);
!     }
!   }    
!   else {
!     if (scp->mohawk) {
!       /* Check whether hash table is full */
!       XE_SELECT_PAGE(0x58);
!       for (i = 0x08; i < 0x10; i++)
! 	if (XE_INB(i) != 0xff)
! 	  break;
!       if (i == 0x10) {
! 	/* Hash table full - enable promiscuous multicast matching */
! 	XE_SELECT_PAGE(0x42);
! 	XE_OUTB(XE_SWC1, (XE_INB(XE_SWC1) & ~XE_SWC1_IA_ENABLE) | XE_SWC1_ALLMULTI);
! 	XE_SELECT_PAGE(0x02);
! 	XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~XE_MSR_HASH_TABLE);
!       }
!       else {
! 	/* Enable hash table and Individual Address matching */
! 	XE_SELECT_PAGE(0x42);
! 	XE_OUTB(XE_SWC1, (XE_INB(XE_SWC1) & ~XE_SWC1_ALLMULTI) | XE_SWC1_IA_ENABLE);
! 	XE_SELECT_PAGE(0x02);
! 	XE_OUTB(XE_MSR, XE_INB(XE_MSR) | XE_MSR_HASH_TABLE);
!       }
!     }
!     else {
!       /* Enable promiscuous multicast matching */
!       XE_SELECT_PAGE(0x42);
!       XE_OUTB(XE_SWC1, (XE_INB(XE_SWC1) & ~XE_SWC1_IA_ENABLE) | XE_SWC1_ALLMULTI);
!     }
    }
+ 
    XE_SELECT_PAGE(0);
  }
  
  
  /*
!  * Copy the Ethernet multicast address in addr to the on-chip registers for
!  * Individual Address idx.  Assumes that addr is really a multicast address
!  * and that idx > 0 (slot 0 is always used for the card MAC address).
   */
  static void
! xe_set_addr(struct xe_softc *scp, u_int8_t* addr, unsigned idx) {
!   u_int8_t page, reg;
!   unsigned i;
  
!   /*
!    * Individual Addresses are stored in registers 8-F of pages 0x50-0x57.  IA1
!    * therefore starts at register 0xE on page 0x50.  The expressions below
!    * compute the starting page and register for any IA index > 0.
!    */
!   --idx;
!   page = 0x50 + idx%4 + idx/4*3;
!   reg = 0x0e - 2 * (idx%4);
  
! #if XE_DEBUG > 1
!   device_printf(scp->dev, "set_addr: idx = %u, page = 0x%02x, reg = 0x%02x\n",
! 		idx+1, page, reg);
! #endif
  
!   /*
!    * Copy the IA bytes.  Note that the byte order is reversed for Mohawk and
!    * Dingo wrt. CE2 hardware.
!    */
!   XE_SELECT_PAGE(page);
!   for (i = 0; i < 6; i++) {
! #if XE_DEBUG > 1
!     if (i > 0)
!       printf(":%02x", addr[i]);
!     else
!       device_printf(scp->dev, "set_addr: %02x", addr[0]);
! #endif
!     XE_OUTB(reg, addr[scp->mohawk ? 5 - i : i]);
!     if (++reg == 0x10) {
!       reg = 0x08;
!       XE_SELECT_PAGE(++page);
      }
!   }
! #if XE_DEBUG > 1
!   printf("\n");
  #endif
+ }
  
  
! /*
!  * Set the appropriate bit in the multicast hash table for the supplied
!  * Ethernet multicast address addr.  Assumes that addr is really a multicast
!  * address.
!  */
! static void
! xe_set_hash(struct xe_softc* scp, u_int8_t* addr) {
!   u_int32_t crc = 0xffffffff;
!   u_int8_t bit, byte, crc31, idx;
!   unsigned i, j;
! 
!   /* Compute CRC of the address -- standard Ethernet CRC function */
!   for (i = 0; i < 6; i++) {
!     byte = addr[i];
!     for (j = 1; j <= 8; j++) {
!       if (crc & 0x80000000)
! 	crc31 = 0x01;
        else
! 	crc31 = 0;
!       bit = crc31 ^ (byte & 0x01);
!       crc <<= 1;
!       byte >>= 1;
!       if (bit)
! 	crc = (crc ^ XE_CRC_POLY)|1;
      }
!   }
! 
! #if XE_DEBUG > 1
!   device_printf(scp->dev, "set_hash: CRC = 0x%08x\n", crc);
  #endif
+ 
+   /* Hash table index = 6 msbs of CRC, reversed */
+   for (i = 0, idx = 0; i < 6; i++) {
+     idx >>= 1;
+     if (crc & 0x80000000) {
+       idx |= 0x20;
+     }
+     crc <<= 1;
    }
  
!   /* Top 3 bits of idx give register - 8, bottom 3 give bit within register */
!   byte = idx >> 3 | 0x08;
!   bit = 0x01 << (idx & 0x07);
! 
! #if XE_DEBUG > 1
!   device_printf(scp->dev, "set_hash: idx = 0x%02x, byte = 0x%02x, bit = 0x%02x\n", idx, byte, bit);
! #endif
! 
!   XE_SELECT_PAGE(0x58);
!   XE_OUTB(byte, XE_INB(byte) | bit);
  }
  
  
***************
*** 1460,1466 ****
     * out the packet.  I guess it is then sent automatically (?)
     */
    if (scp->mohawk)
!     XE_OUTB(XE_CR, XE_CR_TX_PACKET|XE_CR_ENABLE_INTR);
    else
      while (pad > 0) {
        XE_OUTW(XE_EDP, 0xdead);
--- 1564,1570 ----
     * out the packet.  I guess it is then sent automatically (?)
     */
    if (scp->mohawk)
!     XE_OUTB(XE_CR, XE_CR_TX_PACKET | XE_CR_RESTART_TX | XE_CR_ENABLE_INTR);
    else
      while (pad > 0) {
        XE_OUTW(XE_EDP, 0xdead);
***************
*** 1470,1528 ****
    return 0;
  }
  
- /*
-  * Compute the 32-bit Ethernet CRC for the given buffer.
-  */
- static u_int32_t
- xe_compute_crc(u_int8_t *data, int len) {
-   u_int32_t crc = 0xffffffff;
-   u_int32_t poly = 0x04c11db6;
-   u_int8_t current, crc31, bit;
-   int i, k;
- 
-   for (i = 0; i < len; i++) {
-     current = data[i];
-     for (k = 1; k <= 8; k++) {
-       if (crc & 0x80000000) {
- 	crc31 = 0x01;
-       }
-       else {
- 	crc31 = 0;
-       }
-       bit = crc31 ^ (current & 0x01);
-       crc <<= 1;
-       current >>= 1;
-       if (bit) {
- 	crc = (crc ^ poly)|1;
-       }
-     }
-   }
-   return crc;
- }
- 
- 
- /*
-  * Convert a CRC into an index into the multicast hash table.  What we do is
-  * take the most-significant 6 bits of the CRC, reverse them, and use that as
-  * the bit number in the hash table.  Bits 5:3 of the result give the byte
-  * within the table (0-7); bits 2:0 give the bit number within that byte (also 
-  * 0-7), ie. the number of shifts needed to get it into the lsb position.
-  */
- static int
- xe_compute_hashbit(u_int32_t crc) {
-   u_int8_t hashbit = 0;
-   int i;
- 
-   for (i = 0; i < 6; i++) {
-     hashbit >>= 1;
-     if (crc & 0x80000000) {
-       hashbit &= 0x80;
-     }
-     crc <<= 1;
-   }
-   return (hashbit >> 2);
- }
- 
  
  
  /**************************************************************
--- 1574,1579 ----
***************
*** 1790,1796 ****
  }
  
  
! #ifdef XE_DEBUG
  /*
   * A bit of debugging code.
   */
--- 1841,1847 ----
  }
  
  
! #if XE_DEBUG > 2
  /*
   * A bit of debugging code.
   */
***************
*** 1857,1862 ****
--- 1908,1917 ----
  	struct xe_softc *sc = device_get_softc(dev);
  	int start, err;
  
+ #if XE_DEBUG > 1
+ 	device_printf(dev, "activate\n");
+ #endif
+ 
  	if (!sc->dingo) {
  		sc->port_rid = 0;	/* 0 is managed by pccard */
  		sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
***************
*** 1921,1926 ****
--- 1976,1985 ----
  {
  	struct xe_softc *sc = device_get_softc(dev);
  	
+ #if XE_DEBUG > 1
+ 	device_printf(dev, "deactivate\n");
+ #endif
+ 
  	if (sc->intrhand)
  		bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
  	sc->intrhand = 0;
Index: src/sys/dev/xe/if_xereg.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/xe/if_xereg.h,v
retrieving revision 1.5
retrieving revision 1.5.10000.1
diff -c -r1.5 -r1.5.10000.1
*** src/sys/dev/xe/if_xereg.h	10 Jan 2000 08:05:53 -0000	1.5
--- src/sys/dev/xe/if_xereg.h	25 Mar 2003 21:02:31 -0000	1.5.10000.1
***************
*** 24,30 ****
   * SUCH DAMAGE.
   *
   *	$Id: if_xereg.h,v 1.5 1999/05/20 21:53:58 scott Exp $
!  * $FreeBSD: src/sys/dev/xe/if_xereg.h,v 1.5 2000/01/10 08:05:53 imp Exp $
   */
  #ifndef DEV_XE_IF_XEREG_H
  #define DEV_XE_IF_XEREG_H
--- 24,30 ----
   * SUCH DAMAGE.
   *
   *	$Id: if_xereg.h,v 1.5 1999/05/20 21:53:58 scott Exp $
!  * $FreeBSD: src/sys/dev/xe/if_xereg.h,v 1.5.10000.1 2003/03/25 21:02:31 scott Exp $
   */
  #ifndef DEV_XE_IF_XEREG_H
  #define DEV_XE_IF_XEREG_H
***************
*** 283,293 ****
--- 283,297 ----
  #define XE_IMR0_TX_OVERFLOW	0x01	/* Masks for bits in ISR */
  #define XE_IMR0_TX_PACKET	0x02
  #define XE_IMR0_MAC_INTR	0x04
+ #define XE_IMR0_TX_RESGRANT 0x08	/* Tx reservation granted (CE2) */
  #define XE_IMR0_RX_EARLY	0x10
  #define XE_IMR0_RX_PACKET	0x20
  #define XE_IMR0_RX_REJECT	0x40
  #define XE_IMR0_FORCE_INTR	0x80
  
+ /* XE_IMR1 bits */
+ #define XE_IMR1_TX_UNDERRUN	0x01
+ 
  /* XE_ECR bits */
  #define XE_ECR_EARLY_TX		0x01	/* Enable early transmit mode */
  #define XE_ECR_EARLY_RX		0x02	/* Enable early receive mode */
***************
*** 366,379 ****
  
  /* XE_GPR0 bits */
  #define XE_GPR0_GP1_OUT		0x01	/* Value written to GP1 line */
! #define XE_GPR0_GP2_OUT		0x02	/* Value wirtten to GP2 line */
  #define XE_GPR0_GP1_SELECT	0x04	/* 1 = GP1 is output, 0 = GP1 is input */
  #define XE_GPR0_GP2_SELECT	0x08	/* 1 = GP2 is output, 0 = GP2 is input */
  #define XE_GPR0_GP1_IN		0x10	/* Value read from GP1 line */
  #define XE_GPR0_GP2_IN		0x20	/* Value read from GP2 line */
  
  /* XE_GPR1 bits */
! #define XE_GPR1_POWER_DOWN	0x01	/* Power down analog section (down to 20mA load) */
  
  /* XE_BOV values */
  #define XE_BOV_DINGO		0x55	/* Dingo in Dingo mode */
--- 370,384 ----
  
  /* XE_GPR0 bits */
  #define XE_GPR0_GP1_OUT		0x01	/* Value written to GP1 line */
! #define XE_GPR0_GP2_OUT		0x02	/* Value written to GP2 line */
  #define XE_GPR0_GP1_SELECT	0x04	/* 1 = GP1 is output, 0 = GP1 is input */
  #define XE_GPR0_GP2_SELECT	0x08	/* 1 = GP2 is output, 0 = GP2 is input */
  #define XE_GPR0_GP1_IN		0x10	/* Value read from GP1 line */
  #define XE_GPR0_GP2_IN		0x20	/* Value read from GP2 line */
  
  /* XE_GPR1 bits */
! #define XE_GPR1_POWER_DOWN	0x01	/* 0 = Power down analog section */
! #define XE_GPR1_AIC			0x04	/* AIC bit (CE2 only) */
  
  /* XE_BOV values */
  #define XE_BOV_DINGO		0x55	/* Dingo in Dingo mode */
***************
*** 471,476 ****
--- 476,482 ----
  #define XE_TXST1_LINK_STATUS	0x10	/* Valid link status */
  
  /* RX0Msk bits */
+ #define XE_RX0M_MP			0x01	/* Multicast packet? (CE2 only) */
  #define XE_RX0M_LONG_PACKET	0x02	/* Masks for bits in RXST0 */
  #define XE_RX0M_ALIGN_ERROR	0x04	/* Alignment error (CE2 only) */
  #define XE_RX0M_CRC_ERROR	0x08
***************
*** 504,509 ****
--- 510,516 ----
  #define XE_SWC0_LOOPBACK_SOURCE	0x02	/* 1 = Transceiver, 0 = MAC */
  #define XE_SWC0_ACCEPT_ERROR	0x04	/* Accept otherwise OK packets with CRC errors */
  #define XE_SWC0_ACCEPT_SHORT	0x08	/* Accept otherwise OK packets that are too short */
+ #define XE_SWC0_NO_SRC_INSERT	0x20	/* Disable source insertion (CE2) */
  #define XE_SWC0_NO_CRC_INSERT	0x40	/* Don't add CRC to outgoing packets */
  
  /* SWC1 bits */
Index: src/sys/dev/xe/if_xevar.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/xe/if_xevar.h,v
retrieving revision 1.3
retrieving revision 1.3.10000.1
diff -c -r1.3 -r1.3.10000.1
*** src/sys/dev/xe/if_xevar.h	20 Feb 2002 14:23:58 -0000	1.3
--- src/sys/dev/xe/if_xevar.h	6 Apr 2003 12:12:52 -0000	1.3.10000.1
***************
*** 24,30 ****
   * SUCH DAMAGE.
   *
   *	$Id: if_xe.c,v 1.20 1999/06/13 19:17:40 scott Exp $
!  * $FreeBSD: src/sys/dev/xe/if_xevar.h,v 1.3 2002/02/20 14:23:58 shiba Exp $
   */
  #ifndef DEV_XE_IF_XEDEV_H
  #define DEV_XE_IF_XEDEV_H
--- 24,30 ----
   * SUCH DAMAGE.
   *
   *	$Id: if_xe.c,v 1.20 1999/06/13 19:17:40 scott Exp $
!  * $FreeBSD: src/sys/dev/xe/if_xevar.h,v 1.3.10000.1 2003/04/06 12:12:52 scott Exp $
   */
  #ifndef DEV_XE_IF_XEDEV_H
  #define DEV_XE_IF_XEDEV_H
***************
*** 52,59 ****
    int srev;     	/* Silicon revision */
    int tx_queued;	/* Packets currently waiting to transmit */
    int tx_tpr;		/* Last value of TPR reg on card */
-   int tx_collisions;	/* Collisions since last successful send */
    int tx_timeouts;	/* Count of transmit timeouts */
    int autoneg_status;	/* Autonegotiation progress state */
    int media;		/* Private media word */
    u_char version;	/* Bonding Version register from card */
--- 52,59 ----
    int srev;     	/* Silicon revision */
    int tx_queued;	/* Packets currently waiting to transmit */
    int tx_tpr;		/* Last value of TPR reg on card */
    int tx_timeouts;	/* Count of transmit timeouts */
+   u_int16_t tx_thres;	/* Threshold bytes for early transmit */
    int autoneg_status;	/* Autonegotiation progress state */
    int media;		/* Private media word */
    u_char version;	/* Bonding Version register from card */


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list