[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
pci patch needs broad testing
- To: tech_(_at_)_openbsd_(_dot_)_org
- Subject: pci patch needs broad testing
- From: Claudio Jeker <claudio_(_at_)_openbsd_(_dot_)_org>
- Date: Tue, 30 Nov 2004 00:06:42 +0059
- Mail-followup-to: Claudio Jeker <claudio_(_at_)_openbsd_(_dot_)_org>, tech_(_at_)_openbsd_(_dot_)_org
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