Subject: kern/9286: ex driver cannot wake 3c905B from power state D3
To: None <gnats-bugs@gnats.netbsd.org>
From: None <steven_grunza@ieee.org>
List: netbsd-bugs
Date: 01/24/2000 10:09:41
>Number:         9286
>Category:       kern
>Synopsis:       Win98 warm boot puts 3c905B in state D3 and causes ex driver failure
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Jan 24 10:09:00 2000
>Last-Modified:
>Originator:     Steven Grunza
>Organization:
	
>Release:        NetBSD-i386 1.4.1
>Environment:
Dell Dimension xps R400, dual boot to Windows 98 or NetBSD

System: NetBSD pc-grunza-p 1.4.1 NetBSD 1.4.1 (xps_r400) #15: Mon Jan 24 12:46:01 EST 2000 root@pc-grunza-p:/usr/src/sys/arch/i386/compile/xps_r400 i386


>Description:
After choosing to restart in Windows98, the ex driver cannot wake the 3c905B 
from power state D3.  This may also be a problem with recent Linux releases.
>How-To-Repeat:
Warm boot the system from Windows98.
>Fix:
The following patch to /sys/dev/pci/if_ex_pci.c fixes the problem for me:


102a103
> void ex_d3tod0 __P(( struct ex_softc	*, struct pci_attach_args *));
177a179,223
> ex_d3tod0( sc, pa )
> 	struct ex_softc		*sc;
> 	struct pci_attach_args	*pa;
> {
> 
> #define PCI_CACHE_LAT_BIST	0x0c
> #define PCI_BAR0		0x10
> #define PCI_BAR1		0x14
> #define PCI_BAR2		0x18
> #define PCI_BAR3		0x1C
> #define PCI_BAR4		0x20
> #define PCI_BAR5		0x24
> #define PCI_EXP_ROM_BAR		0x30
> #define PCI_INT_GNT_LAT		0x3c
> 
> 
>    pci_chipset_tag_t		pc = pa->pa_pc;
> 
>    u_int32_t			base0;
>    u_int32_t			base1;
>    u_int32_t			romaddr;
>    u_int32_t			pci_command;
>    u_int32_t			pci_int_lat;
>    u_int32_t			pci_cache_lat;
> 
>    pci_command	= pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG );
>    base0	= pci_conf_read(pc, pa->pa_tag, PCI_BAR0 );
>    base1	= pci_conf_read(pc, pa->pa_tag, PCI_BAR1 );
>    romaddr	= pci_conf_read(pc, pa->pa_tag, PCI_EXP_ROM_BAR );
>    pci_cache_lat= pci_conf_read(pc, pa->pa_tag, PCI_CACHE_LAT_BIST );
>    pci_int_lat	= pci_conf_read(pc, pa->pa_tag, PCI_INT_GNT_LAT );
> 
>    pci_conf_write(pc, pa->pa_tag, PCI_POWERCTL, 0);
>    pci_conf_write(pc, pa->pa_tag, PCI_BAR0, base0 );
>    pci_conf_write(pc, pa->pa_tag, PCI_BAR1, base1 );
>    pci_conf_write(pc, pa->pa_tag, PCI_EXP_ROM_BAR, romaddr );
>    pci_conf_write(pc, pa->pa_tag, PCI_INT_GNT_LAT, pci_int_lat );
>    pci_conf_write(pc, pa->pa_tag, PCI_CACHE_LAT_BIST, pci_cache_lat );
>    pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 
> 			  ( PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE));
> 
>    return;
> }
> 
> void
226,228c272,279
< 			printf("%s: unable to wake up from power state D3\n",
< 			    sc->sc_dev.dv_xname);
< 			return;
---
> 			printf("%s: found in power state D3, "
> 			       "attempting to recover.\n",
> 			       sc->sc_dev.dv_xname);
> 
> 			ex_d3tod0( sc, pa );
> 
> 			printf("%s: finished changing power state to D0.\n",
> 			       sc->sc_dev.dv_xname);

The 3c905B and 3c905C documentation says that all PCI configuration is lost in
power state D3 but doesn't say what to do to recover.  Don Becker's linux
driver seems to DTRT.  He has information at http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html.

Steven Grunza
steven_grunza@ieee.org
>Audit-Trail:
>Unformatted: