[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

pci patch needs broad testing



Hi,

this patch adds powerhooks to pci(4) and some additional devices and solves
wakeup problems seen on some laptops. The patch affects ALL machines with
pci bus and needs therefor some broad testing. To be clear this does not
only affect laptops and i386.

You need to apply the patch in /usr/src/sys.
Please send success stories to me and not to the list.
-- 
:wq Claudio

Index: dev/pci/if_em.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.c,v
retrieving revision 1.32
diff -u -p -r1.32 if_em.c
--- dev/pci/if_em.c	16 Nov 2004 14:39:14 -0000	1.32
+++ dev/pci/if_em.c	29 Nov 2004 19:59:18 -0000
@@ -208,6 +208,7 @@ void em_intr(void *);
 int  em_probe(struct device *, void *, void *);
 void em_attach(struct device *, struct device *, void *);
 int  em_intr(void *);
+void em_power(int, void *);
 #endif /* __OpenBSD__ */
 void em_start(struct ifnet *);
 void em_start_locked(struct ifnet *);
@@ -661,6 +662,7 @@ em_attach(struct device *parent, struct 
 	return(0);
 #endif
 #ifdef __OpenBSD__
+	sc->sc_powerhook = powerhook_establish(em_power, sc);
 	return;
 #endif
 
@@ -679,6 +681,21 @@ err_sysctl:
 #endif /* __FreeBSD__ */
 
 }
+
+#ifdef __OpenBSD__
+void
+em_power(int why, void *arg)
+{
+	struct em_softc *sc = (struct em_softc *)arg;
+	struct ifnet *ifp;
+
+	if (why == PWR_RESUME) {
+		ifp = &sc->interface_data.ac_if;
+		if (ifp->if_flags & IFF_UP)
+			em_init(sc);
+	}
+}
+#endif
 
 /*********************************************************************
  *  Device removal routine
Index: dev/pci/if_em.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.h,v
retrieving revision 1.8
diff -u -p -r1.8 if_em.h
--- dev/pci/if_em.h	16 Nov 2004 14:39:14 -0000	1.8
+++ dev/pci/if_em.h	29 Nov 2004 19:59:18 -0000
@@ -326,7 +326,7 @@ struct em_softc {
 	struct timeout	em_intr_enable;
 	struct timeout	timer_handle;
 	struct timeout	tx_fifo_timer_handle;
-
+	void		*sc_powerhook;
 #endif /* __OpenBSD__ */
 
 #ifdef __STRICT_ALIGNMENT
Index: dev/pci/if_ipw.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_ipw.c,v
retrieving revision 1.28
diff -u -p -r1.28 if_ipw.c
--- dev/pci/if_ipw.c	24 Nov 2004 21:27:50 -0000	1.28
+++ dev/pci/if_ipw.c	29 Nov 2004 22:15:41 -0000
@@ -79,6 +79,7 @@ static const struct ieee80211_rateset ip
 
 int ipw_match(struct device *, void *, void *);
 void ipw_attach(struct device *, struct device *, void *);
+void ipw_power(int, void *);
 int ipw_detach(struct device *, int);
 int ipw_media_change(struct ifnet *);
 void ipw_media_status(struct ifnet *, struct ifmediareq *);
@@ -261,6 +262,7 @@ ipw_attach(struct device *parent, struct
 		ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
 	}
 
+	sc->powerhook = powerhook_establish(ipw_power, sc);
 	/* default to authmode OPEN */
 	sc->authmode = IEEE80211_AUTH_OPEN;
 
@@ -295,6 +297,19 @@ ipw_attach(struct device *parent, struct
 	sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
 	sc->sc_txtap.wt_ihdr.it_present = htole32(IPW_TX_RADIOTAP_PRESENT);
 #endif
+}
+
+void
+ipw_power(int why, void *arg)
+{
+	struct ipw_softc *sc = (struct ipw_softc *)arg;
+	struct ifnet *ifp;
+
+	if (why == PWR_RESUME) {
+		ifp = &sc->sc_ic.ic_if;
+		if (ifp->if_flags & IFF_UP)
+			ipw_init(ifp);
+	}
 }
 
 int
Index: dev/pci/if_ipwvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_ipwvar.h,v
retrieving revision 1.4
diff -u -p -r1.4 if_ipwvar.h
--- dev/pci/if_ipwvar.h	18 Nov 2004 21:02:42 -0000	1.4
+++ dev/pci/if_ipwvar.h	29 Nov 2004 19:51:50 -0000
@@ -154,6 +154,7 @@ struct ipw_softc {
 #define sc_txtap	sc_txtapu.th
 	int				sc_txtap_len;
 #endif
+	void				*powerhook;
 };
 
 #define SIOCGRADIO	_IOWR('i', 139, struct ifreq)
Index: dev/pci/if_wi_pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_wi_pci.c,v
retrieving revision 1.39
diff -u -p -r1.39 if_wi_pci.c
--- dev/pci/if_wi_pci.c	23 Nov 2004 21:12:23 -0000	1.39
+++ dev/pci/if_wi_pci.c	29 Nov 2004 22:58:54 -0000
@@ -81,9 +81,15 @@ int	wi_pci_tmd_attach(struct pci_attach_
 int	wi_pci_native_attach(struct pci_attach_args *pa, struct wi_softc *sc);
 int	wi_pci_common_attach(struct pci_attach_args *pa, struct wi_softc *sc);
 void	wi_pci_plx_print_cis(struct wi_softc *);
+void	wi_pci_power(int, void *);
+
+struct wi_pci_softc {
+	struct wi_softc		 sc_wi;		/* real softc */
+	void			*sc_powerhook;
+};
 
 struct cfattach wi_pci_ca = {
-	sizeof (struct wi_softc), wi_pci_match, wi_pci_attach
+	sizeof (struct wi_pci_softc), wi_pci_match, wi_pci_attach
 };
 
 static const struct wi_pci_product {
@@ -135,6 +141,7 @@ wi_pci_match(struct device *parent, void
 void
 wi_pci_attach(struct device *parent, struct device *self, void *aux)
 {
+	struct wi_pci_softc *psc = (struct wi_pci_softc *)self;
 	struct wi_softc *sc = (struct wi_softc *)self;
 	struct pci_attach_args *pa = aux;
 	const struct wi_pci_product *pp;
@@ -144,6 +151,21 @@ wi_pci_attach(struct device *parent, str
 		return;
 	printf("\n");
 	wi_attach(sc, &wi_func_io);
+
+	psc->sc_powerhook = powerhook_establish(wi_pci_power, sc);
+}
+
+void
+wi_pci_power(int why, void *arg)
+{
+	struct wi_softc *sc = (struct wi_softc *)arg;
+	struct ifnet *ifp;
+
+	if (why == PWR_RESUME) {
+		ifp = &sc->sc_arpcom.ac_if;
+		if (ifp->if_flags & IFF_UP)
+			wi_init(sc);
+	}
 }
 
 /*
Index: dev/pci/pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/pci.c,v
retrieving revision 1.34
diff -u -p -r1.34 pci.c
--- dev/pci/pci.c	25 Jun 2004 08:57:10 -0000	1.34
+++ dev/pci/pci.c	23 Nov 2004 22:41:08 -0000
@@ -38,6 +38,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
+#include <sys/malloc.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -45,25 +46,35 @@
 
 int pcimatch(struct device *, void *, void *);
 void pciattach(struct device *, struct device *, void *);
+void pcipower(int, void *);
 
-#ifdef USER_PCICONF
 struct pci_softc {
 	struct device sc_dev;
 	pci_chipset_tag_t sc_pc;
+	void *sc_powerhook;
+	LIST_HEAD(, pci_dev) sc_devs;
+#ifdef USER_PCICONF
 	int sc_bus;		/* PCI configuration space bus # */
-};
 #endif
+};
+
+#define NMAPREG			((PCI_MAPREG_END - PCI_MAPREG_START) / 4)
+struct pci_dev {
+	LIST_ENTRY(pci_dev) pd_next;
+	struct device *pd_dev;
+	pcitag_t pd_tag;        /* pci register tag */
+	pcireg_t pd_csr;
+	pcireg_t pd_bhlc;
+	pcireg_t pd_int;
+	pcireg_t pd_map[NMAPREG];
+};
 
 #ifdef APERTURE
 extern int allowaperture;
 #endif
 
 struct cfattach pci_ca = {
-#ifndef USER_PCICONF
-	sizeof(struct device), pcimatch, pciattach
-#else
 	sizeof(struct pci_softc), pcimatch, pciattach
-#endif
 };
 
 struct cfdriver pci_cd = {
@@ -133,9 +144,9 @@ pciattach(parent, self, aux)
 	bus_space_tag_t iot, memt;
 	pci_chipset_tag_t pc;
 	int bus, device, maxndevs, function, nfunctions;
-#ifdef USER_PCICONF
 	struct pci_softc *sc = (struct pci_softc *)self;
-#endif
+	struct pci_dev *pd;
+	struct device *dev;
 #ifdef __PCI_BUS_DEVORDER
 	char devs[32];
 	int i;
@@ -154,11 +165,12 @@ pciattach(parent, self, aux)
 	bus = pba->pba_bus;
 	maxndevs = pci_bus_maxdevs(pc, bus);
 
-#ifdef USER_PCICONF
 	sc->sc_pc = pba->pba_pc;
+	LIST_INIT(&sc->sc_devs);
+	sc->sc_powerhook = powerhook_establish(pcipower, sc);
+#ifdef USER_PCICONF
 	sc->sc_bus = bus;
 #endif
-
 	if (bus == 0)
 		pci_isa_bridge_callback = NULL;
 
@@ -276,12 +288,69 @@ pciattach(parent, self, aux)
 			}
 			pa.pa_intrline = PCI_INTERRUPT_LINE(intr);
 
-			config_found_sm(self, &pa, pciprint, pcisubmatch);
+			if ((dev = config_found_sm(self, &pa, pciprint,
+			    pcisubmatch))) {
+				pcireg_t reg;
+
+				/* skip header type != 0 */
+				reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
+				if (PCI_HDRTYPE_TYPE(reg) != 0) {
+					printf("%s: skip: %s\n",
+					    sc->sc_dev.dv_xname, dev->dv_xname);
+					continue;
+				}
+				if (!(pd = malloc(sizeof *pd, M_DEVBUF,
+				    M_NOWAIT)))
+					continue;
+				pd->pd_tag = tag;
+				pd->pd_dev = dev;
+				LIST_INSERT_HEAD(&sc->sc_devs, pd, pd_next);
+			}
 		}
 	}
 
 	if (bus == 0 && pci_isa_bridge_callback != NULL)
 		(*pci_isa_bridge_callback)(pci_isa_bridge_callback_arg);
+}
+
+/* save and restore the pci config space */
+void
+pcipower(int why, void *arg)
+{
+	struct pci_softc *sc = (struct pci_softc *)arg;
+	struct pci_dev *pd;
+	pcireg_t reg;
+	int i;
+
+	LIST_FOREACH(pd, &sc->sc_devs, pd_next) {
+		printf("%s: pcipower: %s why %d\n",
+		    sc->sc_dev.dv_xname, pd->pd_dev->dv_xname, why);
+		if (why != PWR_RESUME) {
+			for (i = 0; i < NMAPREG; i++)
+			       pd->pd_map[i] = pci_conf_read(sc->sc_pc,
+				   pd->pd_tag, PCI_MAPREG_START + (i * 4));
+			pd->pd_csr = pci_conf_read(sc->sc_pc, pd->pd_tag,
+			   PCI_COMMAND_STATUS_REG);
+			pd->pd_bhlc = pci_conf_read(sc->sc_pc, pd->pd_tag,
+			   PCI_BHLC_REG);
+			pd->pd_int = pci_conf_read(sc->sc_pc, pd->pd_tag,
+			   PCI_INTERRUPT_REG);
+		} else {
+			for (i = 0; i < NMAPREG; i++)
+				pci_conf_write(sc->sc_pc, pd->pd_tag,
+				    PCI_MAPREG_START + (i * 4),
+					pd->pd_map[i]);
+			reg = pci_conf_read(sc->sc_pc, pd->pd_tag,
+			    PCI_COMMAND_STATUS_REG);
+			pci_conf_write(sc->sc_pc, pd->pd_tag,
+			    PCI_COMMAND_STATUS_REG,
+			    (reg & 0xffff0000) | (pd->pd_csr & 0x0000ffff));
+			pci_conf_write(sc->sc_pc, pd->pd_tag, PCI_BHLC_REG,
+			    pd->pd_bhlc);
+			pci_conf_write(sc->sc_pc, pd->pd_tag, PCI_INTERRUPT_REG,
+			    pd->pd_int);
+		}
+	}
 }
 
 int



Visit your host, monkey.org