Subject: powerhook for wm(4) + ath(4)
To: None <netbsd-users@NetBSD.org>
From: Alexander Becher <abecher@kawo2.rwth-aachen.de>
List: netbsd-users
Date: 08/28/2005 22:49:39
--Boundary_(ID_vnDns2RqMHomvcuGybsKtA)
Content-type: text/plain; charset=iso-8859-1
Content-transfer-encoding: 8BIT
Content-disposition: inline

Hi everyone,

I have attached a patch to add a powerhook to the PCI network
interfaces wm and ath. It is against the netbsd-3 branch. I have drawn
upon if_rtk_pci.c for "inspiration". The patch makes both interfaces
survive an APM suspend/resume on an IBM Thinkpad X40.

I also have a patch for NetBSD 2.0 for both interfaces, but it is not
using pci_conf_capture/pci_conf_restore and is really just a hack (but
it worked).

Annoyingly, the interfaces only become usable after about 30 seconds,
which was not the case with the patch against netbsd-2. The same is
however also true for auich(4), so it's probably due to some other part
of the system.

Maybe someone will find it useful.

Regards
Alexander Becher
-- 
PGP key available
Port Payť / Entgelt bezahlt / Postage Paid: http://www.hashcash.org/

--Boundary_(ID_vnDns2RqMHomvcuGybsKtA)
Content-type: text/plain; charset=us-ascii; NAME=wm+ath-powerhook-netbsd3.patch
Content-transfer-encoding: 7BIT
Content-disposition: attachment; filename=wm+ath-powerhook-netbsd3.patch

Index: if_ath_pci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_ath_pci.c,v
retrieving revision 1.8
diff -u -r1.8 if_ath_pci.c
--- if_ath_pci.c	27 Feb 2005 00:27:32 -0000	1.8
+++ if_ath_pci.c	21 Aug 2005 19:37:52 -0000
@@ -96,7 +96,10 @@
 	struct resource		*sc_sr;		/* memory resource */
 	struct resource		*sc_irq;	/* irq resource */
 #else
+	void			*sc_powerhook;
 	pci_chipset_tag_t	sc_pc;
+	pcitag_t		sc_pcitag;
+	struct pci_conf_state	sc_pciconf;
 #endif
 	void			*sc_ih;		/* intererupt handler */
 	u_int8_t		sc_saved_intline;
@@ -109,6 +112,7 @@
 static int ath_pci_match(struct device *, struct cfdata *, void *);
 static void ath_pci_attach(struct device *, struct device *, void *);
 static void ath_pci_shutdown(void *);
+static void ath_pci_power(int, void *);
 static int ath_pci_detach(struct device *, int);
 
 CFATTACH_DECL(ath_pci,
@@ -225,6 +229,12 @@
 		goto bad3;
 	}
 
+	psc->sc_pcitag = pa->pa_tag;
+	psc->sc_powerhook = powerhook_establish(ath_pci_power, psc);
+	if (psc->sc_powerhook == NULL)
+                aprint_error("%s: WARNING: unable to establish power hook\n",
+                    sc->sc_dev.dv_xname);
+
 	if (ath_attach(ath_product(pa->pa_id), sc) == 0)
 		return;
 
@@ -255,3 +265,26 @@
 
 	ath_shutdown(&psc->sc_sc);
 }
+
+static void
+ath_pci_power(int why, void *arg)
+{
+	struct ath_pci_softc *psc = arg;
+	int s;
+
+	s = splnet();
+	switch (why) {
+	case PWR_SUSPEND:
+	case PWR_STANDBY:
+		pci_conf_capture(psc->sc_pc, psc->sc_pcitag, &psc->sc_pciconf);
+		break;
+	case PWR_RESUME:
+		pci_conf_restore(psc->sc_pc, psc->sc_pcitag, &psc->sc_pciconf);
+		break;
+	case PWR_SOFTSUSPEND:
+	case PWR_SOFTSTANDBY:
+	case PWR_SOFTRESUME:
+		break;
+	}
+	splx(s);
+}
Index: if_wm.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wm.c,v
retrieving revision 1.100.2.2
diff -u -r1.100.2.2 if_wm.c
--- if_wm.c	28 Apr 2005 11:03:16 -0000	1.100.2.2
+++ if_wm.c	21 Aug 2005 19:37:52 -0000
@@ -227,6 +227,7 @@
 	bus_dma_tag_t sc_dmat;		/* bus DMA tag */
 	struct ethercom sc_ethercom;	/* ethernet common data */
 	void *sc_sdhook;		/* shutdown hook */
+	void *sc_powerhook;		/* power management hook */
 
 	wm_chip_type sc_type;		/* chip type */
 	int sc_flags;			/* flags; see below */
@@ -235,6 +236,9 @@
 	int sc_flowflags;		/* 802.3x flow control flags */
 
 	void *sc_ih;			/* interrupt cookie */
+	pci_chipset_tag_t sc_pc;	/* PCI chipset tag */
+	pcitag_t sc_pcitag;		/* PCI register tag */
+	struct pci_conf_state sc_pciconf; /* PCI configuration state */
 
 	int sc_ee_addrbits;		/* EEPROM address bits */
 
@@ -495,6 +499,8 @@
 static int	wm_match(struct device *, struct cfdata *, void *);
 static void	wm_attach(struct device *, struct device *, void *);
 
+static void	wm_power(int, void *);
+
 CFATTACH_DECL(wm, sizeof(struct wm_softc),
     wm_match, wm_attach, NULL, NULL);
 
@@ -1299,6 +1305,15 @@
 	if (sc->sc_sdhook == NULL)
 		aprint_error("%s: WARNING: unable to establish shutdown hook\n",
 		    sc->sc_dev.dv_xname);
+
+	sc->sc_pc = pc;
+	sc->sc_pcitag = pa->pa_tag;
+
+	sc->sc_powerhook = powerhook_establish(wm_power, sc);
+	if (sc->sc_powerhook == NULL)
+		aprint_error("%s: WARNING: unable to establish power hook\n",
+		    sc->sc_dev.dv_xname);
+
 	return;
 
 	/*
@@ -3848,3 +3863,26 @@
 	CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ? WMREG_OLD_FCRTL
 						 : WMREG_FCRTL, sc->sc_fcrtl);
 }
+
+static void
+wm_power(int why, void *arg)
+{
+	struct wm_softc *sc = arg;
+	int s;
+
+	s = splnet();
+	switch (why) {
+	case PWR_SUSPEND:
+	case PWR_STANDBY:
+		pci_conf_capture(sc->sc_pc, sc->sc_pcitag, &sc->sc_pciconf);
+		break;
+	case PWR_RESUME:
+		pci_conf_restore(sc->sc_pc, sc->sc_pcitag, &sc->sc_pciconf);
+		break;
+	case PWR_SOFTSUSPEND:
+	case PWR_SOFTSTANDBY:
+	case PWR_SOFTRESUME:
+		break;
+	}
+	splx(s);
+}

--Boundary_(ID_vnDns2RqMHomvcuGybsKtA)--