From mryan01@host251-12.infonet.tufts.edu  Mon May 22 13:25:58 2000
Return-Path: <mryan01@host251-12.infonet.tufts.edu>
Received: from host251-12.infonet.tufts.edu (host251-12.infonet.tufts.edu [130.64.251.12])
	by hub.freebsd.org (Postfix) with ESMTP id ED33B37B715
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 22 May 2000 13:25:56 -0700 (PDT)
	(envelope-from mryan01@host251-12.infonet.tufts.edu)
Received: (from mryan01@localhost)
	by vapre (8.9.3/8.9.3) id QAA00520;
	Mon, 22 May 2000 16:22:56 -0400 (EDT)
	(envelope-from mryan01)
Message-Id: <200005222022.QAA00520@vapre>
Date: Mon, 22 May 2000 16:22:56 -0400 (EDT)
From: mike ryan <mike+fbsd@medianstrip.net>
Sender: mryan01@host251-12.infonet.tufts.edu
To: FreeBSD-gnats-submit@freebsd.org
Subject: [PATCH] fxp device causes lockups after suspend/resume
X-Send-Pr-Version: 3.2

>Number:         18756
>Category:       kern
>Synopsis:       [PATCH] fxp device causes lockups after suspend/resume
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    dg
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon May 22 13:30:01 PDT 2000
>Closed-Date:    Sun Sep 17 15:28:18 PDT 2000
>Last-Modified:  Wed Oct 18 13:50:01 PDT 2000
>Originator:     mike ryan
>Release:        FreeBSD 4.0-STABLE i386
>Organization:
>Environment:

	sony vaio z505hs, recent 4.0-STABLE GENERIC kernel.

>Description:

	with the internal fxp device up and running, the machine will
	lock up after suspend/resume.  a DDB trace indicates an infinite
	loop while waiting for a DMA to complete within the fxp_init
	function in sys/pci/if_fxp.c at line 1518:

   1511         /*
   1512          * Start the config command/DMA.
   1513          */
   1514         fxp_scb_wait(sc);
   1515         CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
   1516         CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
   1517         /* ...and wait for it to complete. */
   1518         while (!(cbp->cb_status & FXP_CB_STATUS_C));

>How-To-Repeat:

	ifconfig fxp0 up, suspend, and resume.

>Fix:

	the patch below includes code translated from netbsd to avoid
	and log a few infinite loops, including the one above, and to
	avoid trying to handle interrupts before the device is resumed,
	and from linux to save and restore some necessary PCI data.  it
	makes suspend/resume work for me, but i haven't tested it
	anywhere but my laptop.

Index: sys/pci/if_fxp.c
===================================================================
RCS file: /usr/local/src/FREEBSD/src/sys/pci/if_fxp.c,v
retrieving revision 1.77.2.1
diff -c -r1.77.2.1 if_fxp.c
*** sys/pci/if_fxp.c	2000/03/29 02:02:38	1.77.2.1
--- sys/pci/if_fxp.c	2000/05/22 20:01:22
***************
*** 222,227 ****
--- 222,228 ----
  static void fxp_mediastatus	__P((struct ifnet *, struct ifmediareq *));
  static void fxp_set_media	__P((struct fxp_softc *, int));
  static __inline void fxp_scb_wait __P((struct fxp_softc *));
+ static __inline void fxp_dma_wait __P((volatile u_int16_t *, struct fxp_softc *sc));
  static FXP_INTR_TYPE fxp_intr	__P((void *));
  static void fxp_start		__P((struct ifnet *));
  static int fxp_ioctl		__P((struct ifnet *,
***************
*** 291,299 ****
  {
  	int i = 10000;
  
! 	while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
  }
  
  /*************************************************************
   * Operating system-specific autoconfiguration glue
   *************************************************************/
--- 292,316 ----
  {
  	int i = 10000;
  
! 	while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i)
! 		DELAY(2);
! 	if (i == 0)
! 		printf(FXP_FORMAT ": SCB timeout\n", FXP_ARGS(sc));
  }
  
+ static __inline void
+ fxp_dma_wait(status, sc)
+ 	volatile u_int16_t *status;
+ 	struct fxp_softc *sc;
+ {
+ 	int i = 10000;
+ 
+ 	while (!(*status & FXP_CB_STATUS_C) && --i)
+ 		DELAY(2);
+ 	if (i == 0)
+ 		printf(FXP_FORMAT ": DMA timeout\n", FXP_ARGS(sc));
+ }
+ 
  /*************************************************************
   * Operating system-specific autoconfiguration glue
   *************************************************************/
***************
*** 680,691 ****
--- 697,773 ----
  	return 0;
  }
  
+ /*
+  * Device suspend routine.  Stop the interface and save some PCI
+  * settings in case the BIOS doesn't restore them properly on
+  * resume.
+  */
+ static int
+ fxp_suspend(device_t dev)
+ {
+ 	struct fxp_softc *sc = device_get_softc(dev);
+ 	int i, s = splimp();
+ 
+ 	fxp_stop(sc);
+ 	
+ 	for (i=0; i<5; i++)
+ 		sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i*4, 4);
+ 	sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4);
+ 	sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1);
+ 	sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
+ 	sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
+ 
+ 	splx(s);
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * Device resume routine.  Restore some PCI settings in case the BIOS
+  * doesn't, re-enable busmastering, and restart the interface if
+  * appropriate.
+  */
+ static int
+ fxp_resume(device_t dev)
+ {
+ 	struct fxp_softc *sc = device_get_softc(dev);
+ 	struct ifnet *ifp = &sc->sc_if;
+ 	u_int16_t pci_command;
+ 	int i, s = splimp();
+ 
+ 	/* better way to do this? */
+ 	for (i=0; i<5; i++)
+ 		pci_write_config(dev, PCIR_MAPS + i*4, sc->saved_maps[i], 4);
+ 	pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4);
+ 	pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1);
+ 	pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1);
+ 	pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1);
+ 
+ 	/* reenable busmastering */
+ 	pci_command = pci_read_config(dev, PCIR_COMMAND, 2);
+ 	pci_command |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
+ 	pci_write_config(dev, PCIR_COMMAND, pci_command, 2);
+ 
+ 	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
+ 	DELAY(10);
+ 
+ 	/* reinitialize interface if necessary */
+ 	if (ifp->if_flags & IFF_UP)
+ 		fxp_init(sc);
+ 
+ 	splx(s);
+ 
+ 	return 0;
+ }
+ 
  static device_method_t fxp_methods[] = {
  	/* Device interface */
  	DEVMETHOD(device_probe,		fxp_probe),
  	DEVMETHOD(device_attach,	fxp_attach),
  	DEVMETHOD(device_detach,	fxp_detach),
  	DEVMETHOD(device_shutdown,	fxp_shutdown),
+ 	DEVMETHOD(device_suspend,	fxp_suspend),
+ 	DEVMETHOD(device_resume,	fxp_resume),
  
  	{ 0, 0 }
  };
***************
*** 1096,1101 ****
--- 1178,1188 ----
  	int claimed = 0;
  #endif
  
+ 	/* don't try to service interrupts when the interface isn't running */
+ 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ 		return;
+ 	}
+ 
  	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
  #if defined(__NetBSD__)
  		claimed = 1;
***************
*** 1358,1363 ****
--- 1445,1453 ----
  	struct fxp_cb_tx *txp;
  	int i;
  
+ 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ 	ifp->if_timer = 0;
+ 
  	/*
  	 * Cancel stats updater.
  	 */
***************
*** 1400,1408 ****
  			panic("fxp_stop: no buffers!");
  		}
  	}
- 
- 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
- 	ifp->if_timer = 0;
  }
  
  /*
--- 1490,1495 ----
***************
*** 1515,1521 ****
  	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
  	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
  	/* ...and wait for it to complete. */
! 	while (!(cbp->cb_status & FXP_CB_STATUS_C));
  
  	/*
  	 * Now initialize the station address. Temporarily use the TxCB
--- 1602,1608 ----
  	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
  	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
  	/* ...and wait for it to complete. */
! 	fxp_dma_wait(&cbp->cb_status, sc);
  
  	/*
  	 * Now initialize the station address. Temporarily use the TxCB
***************
*** 1538,1544 ****
  	fxp_scb_wait(sc);
  	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
  	/* ...and wait for it to complete. */
! 	while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
  
  	/*
  	 * Initialize transmit control block (TxCB) list.
--- 1625,1631 ----
  	fxp_scb_wait(sc);
  	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
  	/* ...and wait for it to complete. */
! 	fxp_dma_wait(&cb_ias->cb_status, sc);
  
  	/*
  	 * Initialize transmit control block (TxCB) list.
***************
*** 1977,1982 ****
--- 2064,2070 ----
  	struct ifnet *ifp = &sc->sc_if;
  	struct ifmultiaddr *ifma;
  	int nmcasts;
+ 	int count;
  
  	/*
  	 * If there are queued commands, we must wait until they are all
***************
*** 2058,2065 ****
  	 * Wait until command unit is not active. This should never
  	 * be the case when nothing is queued, but make sure anyway.
  	 */
  	while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
! 	    FXP_SCB_CUS_ACTIVE) ;
  
  	/*
  	 * Start the multicast setup command.
--- 2146,2159 ----
  	 * Wait until command unit is not active. This should never
  	 * be the case when nothing is queued, but make sure anyway.
  	 */
+ 	count = 100;
  	while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
! 	    FXP_SCB_CUS_ACTIVE && --count)
! 		DELAY(10);
! 	if (count == 0) {
! 		printf(FXP_FORMAT ": command queue timeout\n", FXP_ARGS(sc));
! 		return;
! 	}
  
  	/*
  	 * Start the multicast setup command.
Index: sys/pci/if_fxpvar.h
===================================================================
RCS file: /usr/local/src/FREEBSD/src/sys/pci/if_fxpvar.h,v
retrieving revision 1.9.2.1
diff -c -r1.9.2.1 if_fxpvar.h
*** sys/pci/if_fxpvar.h	2000/03/29 02:02:39	1.9.2.1
--- sys/pci/if_fxpvar.h	2000/05/22 19:58:05
***************
*** 68,73 ****
--- 68,78 ----
  	int phy_primary_device;		/* device type of primary PHY */
  	int phy_10Mbps_only;		/* PHY is 10Mbps-only device */
  	int eeprom_size;		/* size of serial EEPROM */
+ 	u_int32_t saved_maps[5];	/* pci data */
+ 	u_int32_t saved_biosaddr;
+ 	u_int8_t saved_intline;
+ 	u_int8_t saved_cachelnsz;
+ 	u_int8_t saved_lattimer;
  };
  
  /* Macros to ease CSR access. */

>Release-Note:
>Audit-Trail:

From: David Greenman <dg@root.com>
To: mike ryan <mike+fbsd@medianstrip.net>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/18756: [PATCH] fxp device causes lockups after suspend/resume 
Date: Mon, 22 May 2000 13:38:30 -0700

 >  
 >+ 	/* don't try to service interrupts when the interface isn't running */
 >+ 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
 >+ 		return;
 >+ 	}
 >+ 
 >  	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
 
    This could be a problem. If an interrupt occurs, it must be acknowledged
 otherwise you'll be stuck in an infinit loop - PCI interrupts are level
 sensitive and must be cleared in the ISR.
 
 -DG
 
 David Greenman
 Co-founder, The FreeBSD Project - http://www.freebsd.org
 Creator of high-performance Internet servers - http://www.terasolutions.com
 Pave the road of life with opportunities.
 

From: mike ryan <mike+fbsd@medianstrip.net>
To: David Greenman <dg@root.com>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/18756: [PATCH] fxp device causes lockups after suspend/resume
Date: Mon, 22 May 2000 17:14:51 -0400

 on May 22, David Greenman <dg@root.com> wrote:
 > >  
 > >+ 	/* don't try to service interrupts when the interface isn't running */
 > >+ 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
 > >+ 		return;
 > >+ 	}
 > >+ 
 > >  	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
 > 
 >    This could be a problem. If an interrupt occurs, it must be acknowledged
 > otherwise you'll be stuck in an infinit loop - PCI interrupts are level
 > sensitive and must be cleared in the ISR.
 
 the only time i've seen that return executed is when the interrupt
 was for another device sharing the same IRQ that happened to have
 been resumed first -- in my case, an onboard uhci usb controller.
 without the check above, i do get resume lockups in fxp_intr.
 
 i've just been assuming that an fxp can't generate a interrupt
 unless it's running.  if that's not correct, would it be better to
 have a "device suspended" flag in fxp_softc and replace the
 statement above to execute the necessary resume code if the device
 is still suspended?
 
Responsible-Changed-From-To: freebsd-bugs->dg 
Responsible-Changed-By: nra 
Responsible-Changed-When: Wed Jul 19 21:12:22 PDT 2000 
Responsible-Changed-Why:  
dg wrote the fxp driver. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=18756 
State-Changed-From-To: open->closed 
State-Changed-By: dg 
State-Changed-When: Sun Sep 17 15:28:18 PDT 2000 
State-Changed-Why:  
Similar patches with changes by me was committed to -current. It will 
be MFC'ed in a few days. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=18756 

From: =?ISO-8859-1?Q?Mikko_Ty=F6l=E4j=E4rvi?= <mikko@dynas.se>
To: freebsd-gnats-submit@FreeBSD.org, dg@freebsd.org
Cc:  
Subject: Re: kern/18756: [PATCH] fxp device causes lockups after suspend/resume
Date: Wed, 18 Oct 2000 13:42:47 -0700 (PDT)

 Hi!
 
 The MFC promised in the closing message of this PR about a month ago
 did not seem to happen, so I took a shot at it.  It compiles.  It
 seems to work fine on my VAIO Z505JE, where fxp previously stopped
 working after returning from suspend mode.
 
 The patch is larger than it strictly would have to be, as I removed
 all the NetBSD code (it made it easier to diff against -CURRENT).
 
 It would be nice to see fxp on VAIO work in -STABLE.
 
     Regards,
     /Mikko
 
  Mikko Tyljrvi_______________________________________mikko@rsasecurity.com
  RSA Security
 
 --- if_fxpvar.h.orig	Wed Oct 18 13:07:31 2000
 +++ if_fxpvar.h	Wed Oct 18 13:07:41 2000
 @@ -2,9 +2,6 @@
   * Copyright (c) 1995, David Greenman
   * All rights reserved.
   *              
 - * Modifications to support NetBSD:
 - * Copyright (c) 1997 Jason R. Thorpe.  All rights reserved.
 - *                  
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:             
 @@ -39,16 +36,10 @@
   *	 for functional grouping.
   */
  struct fxp_softc {
 -#if defined(__NetBSD__)
 -	struct device sc_dev;		/* generic device structures */
 -	void *sc_ih;			/* interrupt handler cookie */
 -	struct ethercom sc_ethercom;	/* ethernet common part */
 -#else
  	struct arpcom arpcom;		/* per-interface network data */
  	struct resource *mem;		/* resource descriptor for registers */
  	struct resource *irq;		/* resource descriptor for interrupt */
  	void *ih;			/* interrupt handler cookie */
 -#endif /* __NetBSD__ */
  	bus_space_tag_t sc_st;		/* bus space tag */
  	bus_space_handle_t sc_sh;	/* bus space handle */
  	struct mbuf *rfa_headm;		/* first mbuf in receive frame area */
 @@ -68,6 +59,12 @@
  	int phy_primary_device;		/* device type of primary PHY */
  	int phy_10Mbps_only;		/* PHY is 10Mbps-only device */
  	int eeprom_size;		/* size of serial EEPROM */
 +	int suspended;                  /* 0 = normal  1 = suspended (APM) */
 +	u_int32_t saved_maps[5];	/* pci data */
 +	u_int32_t saved_biosaddr;
 +	u_int8_t saved_intline;
 +	u_int8_t saved_cachelnsz;
 +	u_int8_t saved_lattimer;
  };
  
  /* Macros to ease CSR access. */
 @@ -84,19 +81,5 @@
  #define	CSR_WRITE_4(sc, reg, val)					\
  	bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
  
 -/* Deal with slight differences in software interfaces. */
 -#if defined(__NetBSD__)
 -#define	sc_if			sc_ethercom.ec_if
 -#define	FXP_FORMAT		"%s"
 -#define	FXP_ARGS(sc)		(sc)->sc_dev.dv_xname
 -#define	FXP_INTR_TYPE		int
 -#define	FXP_IOCTLCMD_TYPE	u_long
 -#define	FXP_BPFTAP_ARG(ifp)	(ifp)->if_bpf
 -#else /* __FreeBSD__ */
  #define	sc_if			arpcom.ac_if
 -#define	FXP_FORMAT		"fxp%d"
 -#define	FXP_ARGS(sc)		(sc)->arpcom.ac_if.if_unit
 -#define	FXP_INTR_TYPE		void
 -#define	FXP_IOCTLCMD_TYPE	u_long
 -#define	FXP_BPFTAP_ARG(ifp)	ifp
 -#endif /* __NetBSD__ */
 +#define FXP_UNIT(_sc)		(_sc)->arpcom.ac_if.if_unit
 --- if_fxp.c.orig	Wed Oct 18 13:07:22 2000
 +++ if_fxp.c	Wed Oct 18 13:13:49 2000
 @@ -2,7 +2,7 @@
   * Copyright (c) 1995, David Greenman
   * All rights reserved.
   *
 - * Modifications to support NetBSD and media selection:
 + * Modifications to support media selection:
   * Copyright (c) 1997 Jason R. Thorpe.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
 @@ -51,34 +51,6 @@
  #endif
  
  #include <net/bpf.h>
 -
 -#if defined(__NetBSD__)
 -
 -#include <sys/ioctl.h>
 -#include <sys/errno.h>
 -#include <sys/device.h>
 -
 -#include <net/if_dl.h>
 -#include <net/if_ether.h>
 -
 -#include <netinet/if_inarp.h>
 -
 -#include <vm/vm.h>
 -
 -#include <machine/cpu.h>
 -#include <machine/bus.h>
 -#include <machine/intr.h>
 -
 -#include <dev/pci/if_fxpreg.h>
 -#include <dev/pci/if_fxpvar.h>
 -
 -#include <dev/pci/pcivar.h>
 -#include <dev/pci/pcireg.h>
 -#include <dev/pci/pcidevs.h>
 -
 -
 -#else /* __FreeBSD__ */
 -
  #include <sys/sockio.h>
  #include <sys/bus.h>
  #include <machine/bus.h>
 @@ -97,8 +69,6 @@
  #include <pci/if_fxpreg.h>
  #include <pci/if_fxpvar.h>
  
 -#endif /* __NetBSD__ */
 -
  #ifdef __alpha__		/* XXX */
  /* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
  #undef vtophys
 @@ -219,10 +189,11 @@
  static void fxp_mediastatus	__P((struct ifnet *, struct ifmediareq *));
  static void fxp_set_media	__P((struct fxp_softc *, int));
  static __inline void fxp_scb_wait __P((struct fxp_softc *));
 -static FXP_INTR_TYPE fxp_intr	__P((void *));
 +static __inline void fxp_dma_wait __P((volatile u_int16_t *, struct fxp_softc *sc));
 +static void fxp_intr		__P((void *));
  static void fxp_start		__P((struct ifnet *));
  static int fxp_ioctl		__P((struct ifnet *,
 -				     FXP_IOCTLCMD_TYPE, caddr_t));
 +				     u_long, caddr_t));
  static void fxp_init		__P((void *));
  static void fxp_stop		__P((struct fxp_softc *));
  static void fxp_watchdog	__P((struct ifnet *));
 @@ -288,207 +259,25 @@
  {
  	int i = 10000;
  
 -	while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
 -}
 -
 -/*************************************************************
 - * Operating system-specific autoconfiguration glue
 - *************************************************************/
 -
 -#if defined(__NetBSD__)
 -
 -#ifdef __BROKEN_INDIRECT_CONFIG
 -static int fxp_match __P((struct device *, void *, void *));
 -#else
 -static int fxp_match __P((struct device *, struct cfdata *, void *));
 -#endif
 -static void fxp_attach __P((struct device *, struct device *, void *));
 -
 -static void	fxp_shutdown __P((void *));
 -
 -/* Compensate for lack of a generic ether_ioctl() */
 -static int	fxp_ether_ioctl __P((struct ifnet *,
 -				    FXP_IOCTLCMD_TYPE, caddr_t));
 -#define	ether_ioctl	fxp_ether_ioctl
 -
 -struct cfattach fxp_ca = {
 -	sizeof(struct fxp_softc), fxp_match, fxp_attach
 -};
 -
 -struct cfdriver fxp_cd = {
 -	NULL, "fxp", DV_IFNET
 -};
 -
 -/*
 - * Check if a device is an 82557.
 - */
 -static int
 -fxp_match(parent, match, aux)
 -	struct device *parent;
 -#ifdef __BROKEN_INDIRECT_CONFIG
 -	void *match;
 -#else
 -	struct cfdata *match;
 -#endif
 -	void *aux;
 -{
 -	struct pci_attach_args *pa = aux;
 -
 -	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
 -		return (0);
 -
 -	switch (PCI_PRODUCT(pa->pa_id)) {
 -	case PCI_PRODUCT_INTEL_82557:
 -		return (1);
 -	}
 -
 -	return (0);
 +	while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i)
 +		DELAY(2);
 +	if (i == 0)
 +		printf("fxp%d: SCB timeout\n", FXP_UNIT(sc));
  }
  
 -static void
 -fxp_attach(parent, self, aux)
 -	struct device *parent, *self;
 -	void *aux;
 -{
 -	struct fxp_softc *sc = (struct fxp_softc *)self;
 -	struct pci_attach_args *pa = aux;
 -	pci_chipset_tag_t pc = pa->pa_pc;
 -	pci_intr_handle_t ih;
 -	const char *intrstr = NULL;
 -	u_int8_t enaddr[6];
 -	struct ifnet *ifp;
 -
 -	/*
 -	 * Map control/status registers.
 -	 */
 -	if (pci_mapreg_map(pa, FXP_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0,
 -	    &sc->sc_st, &sc->sc_sh, NULL, NULL)) {
 -		printf(": can't map registers\n");
 -		return;
 -	}
 -	printf(": Intel EtherExpress Pro 10/100B Ethernet\n");
 -
 -	/*
 -	 * Allocate our interrupt.
 -	 */
 -	if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
 -	    pa->pa_intrline, &ih)) {
 -		printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
 -		return;
 -	}
 -	intrstr = pci_intr_string(pc, ih);
 -	sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, fxp_intr, sc);
 -	if (sc->sc_ih == NULL) {
 -		printf("%s: couldn't establish interrupt",
 -		    sc->sc_dev.dv_xname);
 -		if (intrstr != NULL)
 -			printf(" at %s", intrstr);
 -		printf("\n");
 -		return;
 -	}
 -	printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
 -
 -	/* Do generic parts of attach. */
 -	if (fxp_attach_common(sc, enaddr)) {
 -		/* Failed! */
 -		return;
 -	}
 -
 -	printf("%s: Ethernet address %s%s\n", sc->sc_dev.dv_xname,
 -	    ether_sprintf(enaddr), sc->phy_10Mbps_only ? ", 10Mbps" : "");
 -
 -	ifp = &sc->sc_ethercom.ec_if;
 -	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
 -	ifp->if_softc = sc;
 -	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 -	ifp->if_ioctl = fxp_ioctl;
 -	ifp->if_start = fxp_start;
 -	ifp->if_watchdog = fxp_watchdog;
 -
 -	/*
 -	 * Attach the interface.
 -	 */
 -	if_attach(ifp);
 -	/*
 -	 * Let the system queue as many packets as we have available
 -	 * TX descriptors.
 -	 */
 -	ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1;
 -	ether_ifattach(ifp, enaddr);
 -	bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,
 -	    sizeof(struct ether_header));
 -
 -	/*
 -	 * Add shutdown hook so that DMA is disabled prior to reboot. Not
 -	 * doing do could allow DMA to corrupt kernel memory during the
 -	 * reboot before the driver initializes.
 -	 */
 -	shutdownhook_establish(fxp_shutdown, sc);
 -}
 -
 -/*
 - * Device shutdown routine. Called at system shutdown after sync. The
 - * main purpose of this routine is to shut off receiver DMA so that
 - * kernel memory doesn't get clobbered during warmboot.
 - */
 -static void
 -fxp_shutdown(sc)
 -	void *sc;
 -{
 -	fxp_stop((struct fxp_softc *) sc);
 -}
 -
 -static int
 -fxp_ether_ioctl(ifp, cmd, data)
 -	struct ifnet *ifp;
 -	FXP_IOCTLCMD_TYPE cmd;
 -	caddr_t data;
 +static __inline void
 +fxp_dma_wait(status, sc)
 +	volatile u_int16_t *status;
 +	struct fxp_softc *sc;
  {
 -	struct ifaddr *ifa = (struct ifaddr *) data;
 -	struct fxp_softc *sc = ifp->if_softc;
 -
 -	switch (cmd) {
 -	case SIOCSIFADDR:
 -		ifp->if_flags |= IFF_UP;
 -
 -		switch (ifa->ifa_addr->sa_family) {
 -#ifdef INET
 -		case AF_INET:
 -			fxp_init(sc);
 -			arp_ifinit(ifp, ifa);
 -			break;
 -#endif
 -#ifdef NS
 -		case AF_NS:
 -		    {
 -			 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
 -
 -			 if (ns_nullhost(*ina))
 -				ina->x_host = *(union ns_host *)
 -				    LLADDR(ifp->if_sadl);
 -			 else
 -				bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
 -				    ifp->if_addrlen);
 -			 /* Set new address. */
 -			 fxp_init(sc);
 -			 break;
 -		    }
 -#endif
 -		default:
 -			fxp_init(sc);
 -			break;
 -		}
 -		break;
 -
 -	default:
 -		return (EINVAL);
 -	}
 +	int i = 10000;
  
 -	return (0);
 +	while (!(*status & FXP_CB_STATUS_C) && --i)
 +		DELAY(2);
 +	if (i == 0)
 +		printf("fxp%d: DMA timeout\n", FXP_UNIT(sc));
  }
  
 -#else /* __FreeBSD__ */
 -
  /*
   * Return identification string if this is device is ours.
   */
 @@ -684,12 +473,81 @@
  	return 0;
  }
  
 +/*
 + * Device suspend routine.  Stop the interface and save some PCI
 + * settings in case the BIOS doesn't restore them properly on
 + * resume.
 + */
 +static int
 +fxp_suspend(device_t dev)
 +{
 +	struct fxp_softc *sc = device_get_softc(dev);
 +	int i, s = splimp();
 +
 +	fxp_stop(sc);
 +	
 +	for (i=0; i<5; i++)
 +		sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i*4, 4);
 +	sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4);
 +	sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1);
 +	sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
 +	sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
 +
 +	sc->suspended = 1;
 +
 +	splx(s);
 +
 +	return 0;
 +}
 +
 +/*
 + * Device resume routine.  Restore some PCI settings in case the BIOS
 + * doesn't, re-enable busmastering, and restart the interface if
 + * appropriate.
 + */
 +static int
 +fxp_resume(device_t dev)
 +{
 +	struct fxp_softc *sc = device_get_softc(dev);
 +	struct ifnet *ifp = &sc->sc_if;
 +	u_int16_t pci_command;
 +	int i, s = splimp();
 +
 +	/* better way to do this? */
 +	for (i=0; i<5; i++)
 +		pci_write_config(dev, PCIR_MAPS + i*4, sc->saved_maps[i], 4);
 +	pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4);
 +	pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1);
 +	pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1);
 +	pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1);
 +
 +	/* reenable busmastering */
 +	pci_command = pci_read_config(dev, PCIR_COMMAND, 2);
 +	pci_command |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
 +	pci_write_config(dev, PCIR_COMMAND, pci_command, 2);
 +
 +	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
 +	DELAY(10);
 +
 +	/* reinitialize interface if necessary */
 +	if (ifp->if_flags & IFF_UP)
 +		fxp_init(sc);
 +
 +	sc->suspended = 0;
 +
 +	splx(s);
 +
 +	return 0;
 +}
 +
  static device_method_t fxp_methods[] = {
  	/* Device interface */
  	DEVMETHOD(device_probe,		fxp_probe),
  	DEVMETHOD(device_attach,	fxp_attach),
  	DEVMETHOD(device_detach,	fxp_detach),
  	DEVMETHOD(device_shutdown,	fxp_shutdown),
 +	DEVMETHOD(device_suspend,	fxp_suspend),
 +	DEVMETHOD(device_resume,	fxp_resume),
  
  	{ 0, 0 }
  };
 @@ -704,12 +562,6 @@
  
  DRIVER_MODULE(if_fxp, pci, fxp_driver, fxp_devclass, 0, 0);
  
 -#endif /* __NetBSD__ */
 -
 -/*************************************************************
 - * End of operating system-specific autoconfiguration glue
 - *************************************************************/
 -
  /*
   * Do generic parts of attach.
   */
 @@ -797,7 +649,7 @@
  	return (0);
  
   fail:
 -	printf(FXP_FORMAT ": Failed to malloc memory\n", FXP_ARGS(sc));
 +	printf("fxp%d: Failed to malloc memory\n", FXP_UNIT(sc));
  	if (sc->cbl_base)
  		free(sc->cbl_base, M_DEVBUF);
  	if (sc->fxp_stats)
 @@ -1085,7 +937,7 @@
  		 * Pass packet to bpf if there is a listener.
  		 */
  		if (ifp->if_bpf)
 -			bpf_mtap(FXP_BPFTAP_ARG(ifp), mb_head);
 +			bpf_mtap(ifp, mb_head);
  	}
  
  	/*
 @@ -1101,21 +953,18 @@
  /*
   * Process interface interrupts.
   */
 -static FXP_INTR_TYPE
 +static void
  fxp_intr(arg)
  	void *arg;
  {
  	struct fxp_softc *sc = arg;
  	struct ifnet *ifp = &sc->sc_if;
  	u_int8_t statack;
 -#if defined(__NetBSD__)
 -	int claimed = 0;
 -#endif
 +
 +	if (sc->suspended)
 +		return;
  
  	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
 -#if defined(__NetBSD__)
 -		claimed = 1;
 -#endif
  		/*
  		 * First ACK all the interrupts in this pass.
  		 */
 @@ -1206,9 +1055,6 @@
  			}
  		}
  	}
 -#if defined(__NetBSD__)
 -	return (claimed);
 -#endif
  }
  
  /*
 @@ -1334,6 +1180,9 @@
  	struct fxp_cb_tx *txp;
  	int i;
  
 +	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 +	ifp->if_timer = 0;
 +
  	/*
  	 * Cancel stats updater.
  	 */
 @@ -1376,9 +1225,6 @@
  			panic("fxp_stop: no buffers!");
  		}
  	}
 -
 -	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 -	ifp->if_timer = 0;
  }
  
  /*
 @@ -1393,7 +1239,7 @@
  {
  	struct fxp_softc *sc = ifp->if_softc;
  
 -	printf(FXP_FORMAT ": device timeout\n", FXP_ARGS(sc));
 +	printf("fxp%d: device timeout\n", FXP_UNIT(sc));
  	ifp->if_oerrors++;
  
  	fxp_init(sc);
 @@ -1492,7 +1338,7 @@
  	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
  	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
  	/* ...and wait for it to complete. */
 -	while (!(cbp->cb_status & FXP_CB_STATUS_C));
 +	fxp_dma_wait(&cbp->cb_status, sc);
  
  	/*
  	 * Now initialize the station address. Temporarily use the TxCB
 @@ -1502,13 +1348,9 @@
  	cb_ias->cb_status = 0;
  	cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
  	cb_ias->link_addr = -1;
 -#if defined(__NetBSD__)
 -	bcopy(LLADDR(ifp->if_sadl), (void *)cb_ias->macaddr, 6);
 -#else
  	bcopy(sc->arpcom.ac_enaddr,
  	    (void *)(uintptr_t)(volatile void *)cb_ias->macaddr,
  	    sizeof(sc->arpcom.ac_enaddr));
 -#endif /* __NetBSD__ */
  
  	/*
  	 * Start the IAS (Individual Address Setup) command/DMA.
 @@ -1516,7 +1358,7 @@
  	fxp_scb_wait(sc);
  	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
  	/* ...and wait for it to complete. */
 -	while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
 +	fxp_dma_wait(&cb_ias->cb_status, sc);
  
  	/*
  	 * Initialize transmit control block (TxCB) list.
 @@ -1611,9 +1453,8 @@
  	case FXP_PHY_80C24:
  		break;
  	default:
 -		printf(FXP_FORMAT
 -		    ": warning: unsupported PHY, type = %d, addr = %d\n",
 -		     FXP_ARGS(sc), sc->phy_primary_device,
 +		printf("fxp%d: warning: unsupported PHY, type = %d, addr = %d\n",
 +		     FXP_UNIT(sc), sc->phy_primary_device,
  		     sc->phy_primary_addr);
  	}
  }
 @@ -1814,8 +1655,7 @@
  		DELAY(10);
  
  	if (count <= 0)
 -		printf(FXP_FORMAT ": fxp_mdi_read: timed out\n",
 -		    FXP_ARGS(sc));
 +		printf("fxp%d: fxp_mdi_read: timed out\n", FXP_UNIT(sc));
  
  	return (value & 0xffff);
  }
 @@ -1838,14 +1678,13 @@
  		DELAY(10);
  
  	if (count <= 0)
 -		printf(FXP_FORMAT ": fxp_mdi_write: timed out\n",
 -		    FXP_ARGS(sc));
 +		printf("fxp%d: fxp_mdi_write: timed out\n", FXP_UNIT(sc));
  }
  
  static int
  fxp_ioctl(ifp, command, data)
  	struct ifnet *ifp;
 -	FXP_IOCTLCMD_TYPE command;
 +	u_long command;
  	caddr_t data;
  {
  	struct fxp_softc *sc = ifp->if_softc;
 @@ -1857,10 +1696,8 @@
  	switch (command) {
  
  	case SIOCSIFADDR:
 -#if !defined(__NetBSD__)
  	case SIOCGIFADDR:
  	case SIOCSIFMTU:
 -#endif
  		error = ether_ioctl(ifp, command, data);
  		break;
  
 @@ -1884,27 +1721,6 @@
  	case SIOCADDMULTI:
  	case SIOCDELMULTI:
  		sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
 -#if defined(__NetBSD__)
 -		error = (command == SIOCADDMULTI) ?
 -		    ether_addmulti(ifr, &sc->sc_ethercom) :
 -		    ether_delmulti(ifr, &sc->sc_ethercom);
 -
 -		if (error == ENETRESET) {
 -			/*
 -			 * Multicast list has changed; set the hardware
 -			 * filter accordingly.
 -			 */
 -			if (!sc->all_mcasts)
 -				fxp_mc_setup(sc);
 -			/*
 -			 * fxp_mc_setup() can turn on all_mcasts if we run
 -			 * out of space, so check it again rather than else {}.
 -			 */
 -			if (sc->all_mcasts)
 -				fxp_init(sc);
 -			error = 0;
 -		}
 -#else /* __FreeBSD__ */
  		/*
  		 * Multicast list has changed; set the hardware filter
  		 * accordingly.
 @@ -1918,7 +1734,6 @@
  		if (sc->all_mcasts)
  			fxp_init(sc);
  		error = 0;
 -#endif /* __NetBSD__ */
  		break;
  
  	case SIOCSIFMEDIA:
 @@ -1955,6 +1770,7 @@
  	struct ifnet *ifp = &sc->sc_if;
  	struct ifmultiaddr *ifma;
  	int nmcasts;
 +	int count;
  
  	/*
  	 * If there are queued commands, we must wait until they are all
 @@ -2037,8 +1853,14 @@
  	 * Wait until command unit is not active. This should never
  	 * be the case when nothing is queued, but make sure anyway.
  	 */
 +	count = 100;
  	while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
 -	    FXP_SCB_CUS_ACTIVE) ;
 +	    FXP_SCB_CUS_ACTIVE && --count)
 +	    DELAY(10);
 +	if (count == 0) {
 +		printf("fxp%d: command queue timeout\n", FXP_UNIT(sc));
 +		return;
 +	}
  
  	/*
  	 * Start the multicast setup command.
 
 
>Unformatted:
