From scott@fishballoon.org  Sun Apr  6 08:51:19 2003
Return-Path: <scott@fishballoon.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id A0A9D37B401
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  6 Apr 2003 08:51:19 -0700 (PDT)
Received: from mta02-svc.ntlworld.com (mta02-svc.ntlworld.com [62.253.162.42])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 0260343FBF
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  6 Apr 2003 08:51:17 -0700 (PDT)
	(envelope-from scott@fishballoon.org)
Received: from fishballoon.org ([81.104.195.199]) by mta02-svc.ntlworld.com
          (InterMail vM.4.01.03.37 201-229-121-137-20020806) with ESMTP
          id <20030406155111.PTFQ9882.mta02-svc.ntlworld.com@fishballoon.org>
          for <FreeBSD-gnats-submit@freebsd.org>;
          Sun, 6 Apr 2003 16:51:11 +0100
Received: from tuatara.fishballoon.org (tuatara [192.168.1.6])
	by fishballoon.org (8.12.6p2/8.12.6) with ESMTP id h36FoUGw045989
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 6 Apr 2003 16:50:30 +0100 (BST)
	(envelope-from scott@tuatara.fishballoon.org)
Received: (from scott@localhost)
	by tuatara.fishballoon.org (8.12.7/8.12.6/Submit) id h36FoUI9072246;
	Sun, 6 Apr 2003 16:50:30 +0100 (BST)
	(envelope-from scott)
Message-Id: <200304061550.h36FoUI9072246@tuatara.fishballoon.org>
Date: Sun, 6 Apr 2003 16:50:30 +0100 (BST)
From: Scott Mitchell <scott+freebsd@fishballoon.org>
Reply-To: Scott Mitchell <scott+freebsd@fishballoon.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [PATCH] Update xe driver: multicast, hardware setup, etc.
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         50644
>Category:       kern
>Synopsis:       [PATCH] Update xe driver: multicast, hardware setup, etc.
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    rsm
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Apr 06 09:00:28 PDT 2003
>Closed-Date:    Wed Dec 08 23:00:26 GMT 2004
>Last-Modified:  Wed Dec 08 23:00:26 GMT 2004
>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@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@lovett.com>
-  *
   * Author email: <scott@uk.freebsd.org>
   */
  
  
--- 88,95 ----
   * the CEM56/REM56 support code; and the FreeBSD UK Users' Group for hosting
   * the web pages.
   *
   * Author email: <scott@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:

From: Scott Mitchell <scott+freebsd@fishballoon.org>
To: FreeBSD-gnats-submit@FreeBSD.org
Cc: scott+freebsd@tuatara.fishballoon.org
Subject: Re: kern/50644: [PATCH] Update xe driver: multicast, hardware setup, etc.
Date: Wed, 23 Apr 2003 22:53:54 +0100

 The following patch adds support for CE2 cards to the xe driver.  It works
 for the one such card I have available; I'd be very interested to know if
 anyone else has any luck with it.
 
 The patch should be applied on top of the preceding one.  If, like me,
 you're still stuck using OLDCARD, you'll probably also need the patch in
 kern/51333 (http://www.freebsd.org/cgi/query-pr.cgi?pr=51333).  This forces
 OLDCARD to pass some extra CIS data into the driver, which is needed to
 identify some CE2 cards.
 
 Note that older combo cards such as the CEM28 and CEM33 still won't work.
 I think I have a solution for that, but it needs a bit more work.
 
 	Scott
 
 Index: sys/dev/xe/if_xe.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/dev/xe/if_xe.c,v
 retrieving revision 1.35.10000.3
 diff -u -r1.35.10000.3 if_xe.c
 --- sys/dev/xe/if_xe.c	6 Apr 2003 15:06:24 -0000	1.35.10000.3
 +++ sys/dev/xe/if_xe.c	23 Apr 2003 15:17:07 -0000
 @@ -319,6 +319,7 @@
    scp->tx_tpr = 0;
    scp->tx_timeouts = 0;
    scp->tx_thres = 64;
 +  scp->tx_min = ETHER_MIN_LEN - ETHER_CRC_LEN;
    scp->ifp->if_timer = 0;
  
    /* Soft reset the card */
 @@ -431,7 +432,7 @@
    }
  
  #if XE_DEBUG > 2
 -  device_printf(scp->dev, "start");
 +  device_printf(scp->dev, "start\n");
  #endif
  
    /*
 @@ -702,7 +703,7 @@
        rsr = XE_INB(XE_RSR);
  
  #if XE_DEBUG > 2
 -    device_printf(scp->dev, "intr: ESR=0x%02x, RSR=0x%02x\n", esr, rsr,);
 +    device_printf(scp->dev, "intr: ESR=0x%02x, RSR=0x%02x\n", esr, rsr);
  #endif
  
        /* Make sure packet is a good one */
 @@ -1500,28 +1501,34 @@
   */
  static int
  xe_pio_write_packet(struct xe_softc *scp, struct mbuf *mbp) {
 -  struct mbuf *mbp2;
 -  u_int16_t len, pad, free, ok;
 +  unsigned len, pad;
 +  unsigned char wantbyte;
    u_int8_t *data;
 -  u_int8_t savebyte[2], wantbyte;
 +  u_int8_t savebyte[2];
  
    /* Get total packet length */
 -  for (len = 0, mbp2 = mbp; mbp2 != NULL; len += mbp2->m_len, mbp2 = mbp2->m_next);
 +  if (mbp->m_flags & M_PKTHDR)
 +    len = mbp->m_pkthdr.len;
 +  else {
 +    struct mbuf* mbp2 = mbp;
 +    for (len = 0; mbp2 != NULL; len += mbp2->m_len, mbp2 = mbp2->m_next);
 +  }
 +
 +#if XE_DEBUG > 2
 +  device_printf(scp->dev, "pio_write_packet: len = %u\n", len);
 +#endif
  
    /* Packets < minimum length may need to be padded out */
    pad = 0;
 -  if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
 -    pad = (ETHER_MIN_LEN - ETHER_CRC_LEN - len + 1) >> 1;
 -    len = ETHER_MIN_LEN - ETHER_CRC_LEN;
 +  if (len < scp->tx_min) {
 +    pad = scp->tx_min - len;
 +    len = scp->tx_min;
    }
  
    /* Check transmit buffer space */
    XE_SELECT_PAGE(0);
 -  XE_OUTW(XE_TRS, len+2);
 -  free = XE_INW(XE_TSO);
 -  ok = free & 0x8000;
 -  free &= 0x7fff;
 -  if (free <= len + 2)
 +  XE_OUTW(XE_TRS, len+2);	/* Only effective on rev. 1 CE2 cards */
 +  if ((XE_INW(XE_TSO) & 0x7fff) <= len + 2)
      return 1;
  
    /* Send packet length to card */
 @@ -1544,7 +1551,7 @@
        }
        if (len > 1) {		/* Output contiguous words */
  	bus_space_write_multi_2(scp->bst, scp->bsh, XE_EDP, (u_int16_t *) data,
 -	 len >> 1);
 +				len >> 1);
  	data += len & ~1;
  	len &= 1;
        }
 @@ -1555,21 +1562,30 @@
      }
      mbp = mbp->m_next;
    }
 -  if (wantbyte)			/* Last byte for odd-length packets */
 -    XE_OUTW(XE_EDP, *(u_short *)savebyte);
  
    /*
 -   * For CE3 cards, just tell 'em to send -- apparently the card will pad out
 -   * short packets with random cruft.  Otherwise, write nonsense words to fill 
 -   * out the packet.  I guess it is then sent automatically (?)
 +   * Send last byte of odd-length packets
 +   */
 +  if (wantbyte)
 +    XE_OUTB(XE_EDP, savebyte[0]);
 +
 +  /*
 +   * Can just tell CE3 cards to send; short packets will be padded out with
 +   * random cruft automatically.  For CE2, manually pad the packet with
 +   * garbage; it will be sent when the required number or bytes have been
 +   * delivered to the card.
     */
    if (scp->mohawk)
      XE_OUTB(XE_CR, XE_CR_TX_PACKET | XE_CR_RESTART_TX | XE_CR_ENABLE_INTR);
 -  else
 +  else if (pad > 0) {
 +    if (pad & 0x01)
 +      XE_OUTB(XE_EDP, 0xaa);
 +    pad >>= 1;
      while (pad > 0) {
        XE_OUTW(XE_EDP, 0xdead);
        pad--;
      }
 +  }
  
    return 0;
  }
 Index: sys/dev/xe/if_xe_pccard.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/dev/xe/if_xe_pccard.c,v
 retrieving revision 1.7.10000.1
 diff -u -r1.7.10000.1 if_xe_pccard.c
 --- sys/dev/xe/if_xe_pccard.c	25 Mar 2003 21:02:31 -0000	1.7.10000.1
 +++ sys/dev/xe/if_xe_pccard.c	23 Apr 2003 15:17:58 -0000
 @@ -58,7 +58,7 @@
   * Set XE_DEBUG to enable debug messages
   * Larger values increase verbosity
   */
 -#define XE_DEBUG 2
 +#define XE_DEBUG 0
  
  #define XE_VENDOR_ID_XIRCOM 0x0105
  #define XE_VENDOR_ID_COMPAQ_1 0x0138
 @@ -81,18 +81,19 @@
  #define XE_CARD_TYPE_FLAGS_CE2 0x1
  #define XE_CARD_TYPE_FLAGS_MOHAWK 0x2
  #define XE_CARD_TYPE_FLAGS_DINGO 0x4
 -#define XE_PROD_UMASK 0x100f
 -#define XE_PROD_MODEM_UMASK 0x1000
 -#define XE_PROD_SINGLE_ID1 0x1
 -#define XE_PROD_SINGLE_ID2 0x2
 -#define XE_PROD_SINGLE_ID3 0x3
 -#define XE_PROD_MULTI_ID1 0x1001
 -#define XE_PROD_MULTI_ID2 0x1002
 -#define XE_PROD_MULTI_ID3 0x1003
 -#define XE_PROD_MULTI_ID4 0x1004
 -#define XE_PROD_MULTI_ID5 0x1005
 -#define XE_PROD_MULTI_ID6 0x1006 
 -#define XE_PROD_MULTI_ID7 0x1007  
 +#define XE_PROD_UMASK 0x11000f
 +#define XE_PROD_ETHER_UMASK 0x010000
 +#define XE_PROD_MODEM_UMASK 0x100000
 +#define XE_PROD_SINGLE_ID1 0x010001
 +#define XE_PROD_SINGLE_ID2 0x010002
 +#define XE_PROD_SINGLE_ID3 0x010003
 +#define XE_PROD_MULTI_ID1 0x110001
 +#define XE_PROD_MULTI_ID2 0x110002
 +#define XE_PROD_MULTI_ID3 0x110003
 +#define XE_PROD_MULTI_ID4 0x110004
 +#define XE_PROD_MULTI_ID5 0x110005
 +#define XE_PROD_MULTI_ID6 0x110006 
 +#define XE_PROD_MULTI_ID7 0x110007  
  
  struct xe_card_type_table {
  	u_int32_t prod_type;
 @@ -137,7 +138,7 @@
  	int rid;
  	int ioport;
  
 -#ifdef XE_DEBUG
 +#if XE_DEBUG > 1
  	device_printf(dev, "cem56fix\n");
  #endif
  
 @@ -218,8 +219,25 @@
  	struct xe_card_type_table *card_itm;
  	int i;
  
 -#ifdef XE_DEBUG
 +#if XE_DEBUG > 1
 +	char* vendor_str = NULL;
 +	char* product_str = NULL;
 +	char* cis4_str = NULL;
  	device_printf(dev, "pccard_probe\n");
 +	pccard_get_vendor(dev, &vendor);
 +	pccard_get_product(dev, &prodid);
 +	pccard_get_prodext(dev, &prodext);
 +	pccard_get_vendor_str(dev, &vendor_str);
 +	pccard_get_product_str(dev, &product_str);
 +	pccard_get_cis3_str(dev, &cis3_str);
 +	pccard_get_cis4_str(dev, &cis4_str);
 +	device_printf(dev, "vendor = 0x%04x\n", vendor);
 +	device_printf(dev, "product = 0x%04x\n", prodid);
 +	device_printf(dev, "prodext = 0x%02x\n", prodext);
 +	device_printf(dev, "vendor_str = %s\n", vendor_str);
 +	device_printf(dev, "product_str = %s\n", product_str);
 +	device_printf(dev, "cis3_str = %s\n", cis3_str);
 +	device_printf(dev, "cis4_str = %s\n", cis4_str);
  #endif
  
  	/*
 @@ -258,7 +276,7 @@
  	 */
  	pccard_get_cis3_str(dev, &cis3_str);
  	if (strcmp(scp->card_type, "CE") == 0)
 -		if (strcmp(cis3_str, "CE2") ==0)
 +		if (cis3_str != NULL && strcmp(cis3_str, "PS-CE2-10") == 0)
  			scp->card_type = "CE2"; /* Look for "CE2" string */
  
  	/*
 @@ -287,7 +305,7 @@
  	struct xe_softc *scp = device_get_softc(dev);
  	int err;
  
 -#ifdef XE_DEBUG
 +#if XE_DEBUG > 1
  	device_printf(dev, "pccard_attach\n");
  #endif
  
 @@ -318,7 +336,7 @@
  {
  	struct xe_softc *sc = device_get_softc(dev);
  
 -#ifdef XE_DEBUG
 +#if XE_DEBUG > 1
  	device_printf(dev, "pccard_detach\n");
  #endif
  
 @@ -348,7 +366,7 @@
  {
  	const struct pccard_product *pp;
  
 -#ifdef XE_DEBUG
 +#if XE_DEBUG > 1
  	device_printf(dev, "pccard_match\n");
  #endif
  
 Index: sys/dev/xe/if_xevar.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/dev/xe/if_xevar.h,v
 retrieving revision 1.3.10000.1
 diff -u -r1.3.10000.1 if_xevar.h
 --- sys/dev/xe/if_xevar.h	6 Apr 2003 12:12:52 -0000	1.3.10000.1
 +++ sys/dev/xe/if_xevar.h	13 Apr 2003 15:28:34 -0000
 @@ -53,6 +53,7 @@
    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_min;	/* Smallest packet we can send without padding */
    u_int16_t tx_thres;	/* Threshold bytes for early transmit */
    int autoneg_status;	/* Autonegotiation progress state */
    int media;		/* Private media word */

From: Scott Mitchell <scott+freebsd@fishballoon.org>
To: FreeBSD-gnats-submit@FreeBSD.org
Cc: scott+freebsd@fishballoon.org
Subject: Re: kern/50644: [PATCH] Update xe driver: multicast, hardware setup, etc.
Date: Sun, 15 Jun 2003 13:08:02 +0100

 This patch adds support for the Ethernet side of the CEM28 and CEM33 10Mbps
 Ethernet/modem combo cards.  The driver now works well with all the cards I
 have to test against (a CE2, CE3, CEM28 and CEM33).
 
 There are a couple of gotchas to be aware of:
 - My CEM28 (and all others, as far as I know) has its MAC address in a
   non-standard location in the CIS.  Ultimately some quirk code will be
   required to deal with this, but for now I've just added 'ether 0x98' to
   the relevant pccard.conf entry.
 - I/O port selection for the CEM28 and CEM33 is a bit crufty -- it needs to
   find a port range adjacent to whichever sio port range the pccard layer
   has picked from the CIS config entries.  I needed to disable one of the
   onboard serial ports on my laptop to free up enough I/O space in the
   right place.  Some combination of disabling ports and picking the right
   CIS config entry will probably be required.
 - I still have no idea how all of this works (or doesn't) with NEWCARD.
 
 	Scott
 
 
 cards.  
 Index: src/sys/dev/xe/if_xe.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/dev/xe/if_xe.c,v
 retrieving revision 1.35.10000.4
 diff -u -r1.35.10000.4 if_xe.c
 --- src/sys/dev/xe/if_xe.c	24 May 2003 17:04:06 -0000	1.35.10000.4
 +++ src/sys/dev/xe/if_xe.c	15 Jun 2003 11:42:39 -0000
 @@ -573,13 +573,22 @@
    ifp = &scp->arpcom.ac_if;
  
    /* Disable interrupts */
 -  XE_OUTB(XE_CR, 0);
 +  if (scp->mohawk)
 +    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) {
 +  while ((isr = XE_INB(XE_ISR)) != 0) {
 +
 +    /* 0xff might mean the card is no longer around */
 +    if (isr == 0xff) {
 +#if XE_DEBUG > 2
 +      device_printf(scp->dev, "intr: interrupt received for missing card?\n");
 +#endif
 +      break;
 +    }
  
      /* Read other status registers */
      XE_SELECT_PAGE(0x40);
 @@ -658,7 +667,7 @@
  	XE_OUTB(XE_CR, XE_CR_RESTART_TX);
        }
        /* Transmit underrun -- increase early transmit threshold */
 -      if (txst0 & XE_TXST0_TX_UNDERRUN) {
 +      if (txst0 & XE_TXST0_TX_UNDERRUN && scp->mohawk) {
  	device_printf(scp->dev, "transmit underrun");
  	if (scp->tx_thres < ETHER_MAX_LEN) {
  	  if ((scp->tx_thres += 64) > ETHER_MAX_LEN)
 @@ -714,6 +723,10 @@
  
  	len = XE_INW(XE_RBC) - ETHER_CRC_LEN;
  
 +#if XE_DEBUG > 2
 +    device_printf(scp->dev, "intr: receive length = %d\n", len);
 +#endif
 +
  	if (len == 0) {
  	  ifp->if_iqdrops++;
  	  continue;
 @@ -807,7 +820,9 @@
  
      /* Clear receiver overruns now we have some free buffer space */
      if (rst0 & XE_RST0_RX_OVERRUN) {
 +#if XE_DEBUG > 0
        device_printf(scp->dev, "receive overrun\n");
 +#endif
        ifp->if_ierrors++;
        scp->mibdata.dot3StatsInternalMacReceiveErrors++;
        XE_OUTB(XE_CR, XE_CR_CLEAR_OVERRUN);
 @@ -1922,17 +1937,18 @@
  xe_activate(device_t dev)
  {
  	struct xe_softc *sc = device_get_softc(dev);
 -	int start, err;
 +	int start, err, i;
  
  #if XE_DEBUG > 1
  	device_printf(dev, "activate\n");
  #endif
  
 -	if (!sc->dingo) {
 +	if (!sc->modem) {
  		sc->port_rid = 0;	/* 0 is managed by pccard */
  		sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
  		    &sc->port_rid, 0, ~0, 16, RF_ACTIVE);
 -	} else {
 +	}
 +	else if (sc->dingo) {
  		/*
  		 * Find a 16 byte aligned ioport for the card.
  		 */
 @@ -1953,12 +1969,59 @@
  			    sc->port_res);
  			start = (rman_get_start(sc->port_res) + 15) & ~0xf;
  		} while (1);
 +#if XE_DEBUG > 1
 +		device_printf(dev, "RealPort port 0x%0lx, size 0x%0lx\n",
 +		    bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
 +		    bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid));
 +#endif /* XE_DEBUG */
 +	}
 +	else if (sc->ce2) {
 +	    /*
 +	     * Find contiguous I/O port for the Ethernet function on CEM2 and
 +	     * CEM3 cards.  We allocate window 0 wherever pccard has decided
 +	     * it should be, then find an available window adjacent to it for
 +	     * the second function.  Not sure that both windows are actually
 +	     * needed.
 +	     */
 +#if XE_DEBUG > 0
 +	    device_printf(dev, "Finding I/O port for CEM2/CEM3\n");
 +#endif
 +	    sc->ce2_port_rid = 0;	/* 0 is managed by pccard */
 +	    sc->ce2_port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
 +						  &sc->ce2_port_rid, 0, ~0,
 +						  8, RF_ACTIVE);
 +	    if (!sc->ce2_port_res) {
 +#if XE_DEBUG > 0
 +		device_printf(dev, "Cannot allocate I/O port for modem\n");
 +#endif
 +		return ENOMEM;
 +	    }
 +
 +	    sc->port_rid = 1;
 +	    start = bus_get_resource_start(dev, SYS_RES_IOPORT,
 +					   sc->ce2_port_rid);
 +	    for (i = 0; i < 2; i++) {
 +		start += (i == 0 ? 8 : -24);
 +		sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
 +						  &sc->port_rid, start,
 +						  start + 18, 18, RF_ACTIVE);
 +		if (sc->port_res == 0)
 +		    continue;	/* Failed, try again if possible */
 +		if (bus_get_resource_start(dev, SYS_RES_IOPORT,
 +					   sc->port_rid) == start)
 +		    break;	/* Success! */
 +
 +		bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid,
 +				     sc->port_res);
 +		sc->port_res = 0;
 +	    }
  #if XE_DEBUG > 2
 -		device_printf(dev, "port 0x%0lx, size 0x%0lx\n",
 +		device_printf(dev, "CEM2/CEM3 port 0x%0lx, size 0x%0lx\n",
  		    bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
  		    bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid));
  #endif /* XE_DEBUG */
  	}
 +
  	if (!sc->port_res) {
  #if XE_DEBUG > 0
  		device_printf(dev, "Cannot allocate ioport\n");
 @@ -1995,6 +2058,7 @@
  #if XE_DEBUG > 1
  	device_printf(dev, "deactivate\n");
  #endif
 +	xe_disable_intr(sc);
  
  	if (sc->intrhand)
  		bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
 @@ -2003,6 +2067,10 @@
  		bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 
  		    sc->port_res);
  	sc->port_res = 0;
 +	if (sc->ce2_port_res)
 +	    bus_release_resource(dev, SYS_RES_IOPORT, sc->ce2_port_rid,
 +				 sc->ce2_port_res);
 +	sc->ce2_port_res = 0;
  	if (sc->irq_res)
  		bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 
  		    sc->irq_res);
 Index: src/sys/dev/xe/if_xe_pccard.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/dev/xe/if_xe_pccard.c,v
 retrieving revision 1.7.10000.2
 diff -u -r1.7.10000.2 if_xe_pccard.c
 --- src/sys/dev/xe/if_xe_pccard.c	24 May 2003 17:04:06 -0000	1.7.10000.2
 +++ src/sys/dev/xe/if_xe_pccard.c	24 May 2003 18:14:19 -0000
 @@ -25,7 +25,7 @@
   *
   *
   * xe pccard interface driver
 - * $FreeBSD: src/sys/dev/xe/if_xe_pccard.c,v 1.7.10000.2 2003/05/24 17:04:06 scott Exp $
 + * $FreeBSD: src/sys/dev/xe/if_xe_pccard.c,v 1.7.10000.1 2003/03/25 21:02:31 scott Exp $
   */
  
  #include <sys/param.h>
 @@ -118,18 +118,19 @@
  /*
   * Prototypes
   */
 -static int xe_cem56fix(device_t dev);
 +static int xe_cemfix(device_t dev);
  static struct xe_vendor_table *xe_vendor_lookup(u_int32_t devid,
  					struct xe_vendor_table *tbl);
  static struct xe_card_type_table *xe_card_type_lookup(u_int32_t devid,
  					struct xe_card_type_table *tbl);
  
  /*
 - * Fixing for RealPort cards - they need a little furtling to get the
 - * ethernet working. But this codes don't work well in NEWCARD.
 + * Fixing for CEM2, CEM3 and CEM56/REM56 cards.  These need some magic to
 + * enable the Ethernet function, which isn't mentioned anywhere in the CIS.
 + * Despite the register names, most of this isn't Dingo-specific.
   */
  static int
 -xe_cem56fix(device_t dev)
 +xe_cemfix(device_t dev)
  {
  	struct xe_softc *sc = (struct xe_softc *) device_get_softc(dev);
  	bus_space_tag_t bst;
 @@ -139,10 +140,10 @@
  	int ioport;
  
  #if XE_DEBUG > 1
 -	device_printf(dev, "cem56fix\n");
 +	device_printf(dev, "cemfix\n");
  #endif
  
 -	device_printf(dev, "Realport port 0x%0lx, size 0x%0lx\n",
 +	device_printf(dev, "CEM I/O port 0x%0lx, size 0x%0lx\n",
  		bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
  		bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid));
  
 @@ -168,12 +169,14 @@
  	bus_space_write_1(bst, bsh, DINGO_EBAR0, ioport & 0xff);
  	bus_space_write_1(bst, bsh, DINGO_EBAR1, (ioport >> 8) & 0xff);
  
 -	bus_space_write_1(bst, bsh, DINGO_DCOR0, DINGO_DCOR0_SF_INT);
 -	bus_space_write_1(bst, bsh, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL |
 -						 DINGO_DCOR1_EEDIO);
 -	bus_space_write_1(bst, bsh, DINGO_DCOR2, 0x00);
 -	bus_space_write_1(bst, bsh, DINGO_DCOR3, 0x00);
 -	bus_space_write_1(bst, bsh, DINGO_DCOR4, 0x00);
 +	if (sc->dingo) {
 +		bus_space_write_1(bst, bsh, DINGO_DCOR0, DINGO_DCOR0_SF_INT);
 +		bus_space_write_1(bst, bsh, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL |
 +						  DINGO_DCOR1_EEDIO);
 +		bus_space_write_1(bst, bsh, DINGO_DCOR2, 0x00);
 +		bus_space_write_1(bst, bsh, DINGO_DCOR3, 0x00);
 +		bus_space_write_1(bst, bsh, DINGO_DCOR4, 0x00);
 +	}
  
  	bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
  
 @@ -313,8 +316,9 @@
  		return (err);
           
  	/* Hack RealPorts into submission */
 -	if (scp->dingo && xe_cem56fix(dev) < 0) {
 -		device_printf(dev, "Unable to fix your RealPort\n");
 +	if (scp->modem && xe_cemfix(dev) < 0) {
 +		device_printf(dev, "Unable to fix your %s combo card\n",
 +					  scp->card_type);
  		xe_deactivate(dev);
  		return (ENODEV);
  	}
 Index: src/sys/dev/xe/if_xevar.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/dev/xe/if_xevar.h,v
 retrieving revision 1.3.10000.2
 diff -u -r1.3.10000.2 if_xevar.h
 --- src/sys/dev/xe/if_xevar.h	24 May 2003 17:04:06 -0000	1.3.10000.2
 +++ src/sys/dev/xe/if_xevar.h	24 May 2003 17:53:36 -0000
 @@ -49,6 +49,8 @@
    int irq_rid;
    struct resource *port_res;
    int port_rid;
 +  struct resource *ce2_port_res;
 +  int ce2_port_rid;
    int srev;     	/* Silicon revision */
    int tx_queued;	/* Packets currently waiting to transmit */
    int tx_tpr;		/* Last value of TPR reg on card */
Responsible-Changed-From-To: freebsd-bugs->imp 
Responsible-Changed-By: bms 
Responsible-Changed-When: Tue 25 Nov 2003 15:58:50 PST 
Responsible-Changed-Why:  
Maybe imp has seen this already? 

http://www.freebsd.org/cgi/query-pr.cgi?pr=50644 
Responsible-Changed-From-To: imp->rsm 
Responsible-Changed-By: bms 
Responsible-Changed-When: Tue 25 Nov 2003 16:26:34 PST 
Responsible-Changed-Why:  
Assigned to rsm at Warner's request. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=50644 
State-Changed-From-To: open->closed 
State-Changed-By: rsm 
State-Changed-When: Wed Dec 8 22:57:22 GMT 2004 
State-Changed-Why:  
Plenty more work to do on the driver, but this patch has been committed. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=50644 
>Unformatted:
