Please test this diff on all pcmcia cards and machines you can find, and report the results directly to me (ie. test the zaurus with brand new -current code, apm i386 laptops, and the other non-suspending cases such as amd64/i386 acpi - but don't test suspend there).
PLEASE do this very soon since I want to move ahead quickly (I am working on making all 4 (zaurus, i386-apm, i386-acpi, amd64-acpi) suspend-resume codepaths use the same driver infastructure; this will remove a butload of special cases. This will not yet make pcmcia suspend/resume correctly on many acpi machines; that requires more diffs which will come once pcmcia is fixed. That's a hint to test this on the other machines soon. There are also some usb changes coming, and then zaurus changes, and then i386 changes fully using the new infrastructure.. and finally, removal of all the powerhook code. I know there are many bugs left in here; there were many here to start with. This diff will be split up when it is commited, but it is better to have it all for testing. A rough summary of the changes: - pcmcia was converting suspend/resume into activate/deactivate to the card drivers. this is WRONG, since the needs of activate and deactivate are different. I have started trying to resolve this in some drivers, and want to get this diff in with a few fixed drivers, so that the others can catch up to the new better way of doing this - some drivers do the pcmcia_function_enable() and interrupt establishment in their xxattach, then do it again in xxactivate. I am trying to work around this now, but not yet happy with the solution - related to the previous comment, a massive amount of #ifdef notyet code in these drivers will be deleted later on, but I wanted to keep this simple for now. - i found a few more drivers which need a workq for resume - to interlock against the ioctl, kettenis wants us to move the tsleep(&sc->wi_flags thing to a rw_lock; someone has to do that work in some other drivers first then I will copy that here. - there are other drivers in other subsystems which use workq and need the interlocks too. is anyone going to help? - pcmcia com continue talking serial in cu after an unsuspend - i have been playing with looping ifconfig's and ping's through suspends - ne works - wi works - malo is causing memory corruption on a re-insert and re-dhclient. I cannot spot the bug. - wdc controllers work fine; no more wdc timeout errors! - wdc at install time requires that softraid be disabled because softraid is walking alldevs searching for disks and then calling a bucketload of functions which sleep. It is a massive bug in softraid. - sm, xe, an, ray are untested, but I will attempt to write diffs for them if someone shows up with hardware Index: pci/if_wi_pci.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_wi_pci.c,v retrieving revision 1.46 diff -u -p -u -r1.46 if_wi_pci.c --- pci/if_wi_pci.c 27 Aug 2010 18:29:44 -0000 1.46 +++ pci/if_wi_pci.c 29 Aug 2010 18:06:17 -0000 @@ -187,7 +187,18 @@ wi_pci_resume(void *arg1, void *arg2) { struct wi_softc *sc = (struct wi_softc *)arg1; + int s; + + s = splnet(); + while (sc->wi_flags & WI_FLAGS_BUSY) + tsleep(&sc->wi_flags, 0, "wipwr", 0); + sc->wi_flags |= WI_FLAGS_BUSY; + wi_init(sc); + + sc->wi_flags &= ~WI_FLAGS_BUSY; + wakeup(&sc->wi_flags); + splx(s); } void Index: ic/if_wi.c =================================================================== RCS file: /cvs/src/sys/dev/ic/if_wi.c,v retrieving revision 1.148 diff -u -p -u -r1.148 if_wi.c --- ic/if_wi.c 2 Jul 2010 02:40:15 -0000 1.148 +++ ic/if_wi.c 29 Aug 2010 18:24:33 -0000 @@ -1544,28 +1544,36 @@ STATIC int wi_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { int s, error = 0, i, j, len; - struct wi_softc *sc; - struct ifreq *ifr; + struct wi_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; struct proc *p = curproc; struct ifaddr *ifa = (struct ifaddr *)data; struct wi_scan_res *res; struct wi_scan_p2_hdr *p2; struct wi_req *wreq = NULL; u_int32_t flags; - struct ieee80211_nwid *nwidp = NULL; struct ieee80211_nodereq_all *na; struct ieee80211_bssid *bssid; s = splnet(); - - sc = ifp->if_softc; - ifr = (struct ifreq *)data; - if (!(sc->wi_flags & WI_FLAGS_ATTACHED)) { + error = ENODEV; + goto fail; + } + + /* + * Prevent processes from entering this function while another + * process is tsleep'ing in it. + */ + while ((sc->wi_flags & WI_FLAGS_BUSY) && error == 0) + error = tsleep(&sc->wi_flags, PCATCH, "wiioc", 0); + if (error != 0) { splx(s); - return(ENODEV); + return error; } + sc->wi_flags |= WI_FLAGS_BUSY; + DPRINTF (WID_IOCTL, ("wi_ioctl: command %lu data %p\n", command, data)); @@ -2032,6 +2040,9 @@ wi_ioctl(struct ifnet *ifp, u_long comma if (nwidp) free(nwidp, M_DEVBUF); +fail: + sc->wi_flags &= ~WI_FLAGS_BUSY; + wakeup(&sc->wi_flags); splx(s); return(error); } Index: ic/if_wivar.h =================================================================== RCS file: /cvs/src/sys/dev/ic/if_wivar.h,v retrieving revision 1.29 diff -u -p -u -r1.29 if_wivar.h --- ic/if_wivar.h 10 Aug 2009 20:29:54 -0000 1.29 +++ ic/if_wivar.h 29 Aug 2010 18:05:03 -0000 @@ -139,6 +139,7 @@ struct wi_softc { #define WI_FLAGS_BUS_USB 0x0400 #define WI_FLAGS_HAS_ENH_SECURITY 0x0800 #define WI_FLAGS_TXPOWER 0x1000 +#define WI_FLAGS_BUSY 0x2000 #define WI_PRT_FMT "%s" #define WI_PRT_ARG(sc) (sc)->sc_dev.dv_xname Index: pcmcia/cfxga.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/cfxga.c,v retrieving revision 1.19 diff -u -p -u -r1.19 cfxga.c --- pcmcia/cfxga.c 13 Oct 2009 19:33:16 -0000 1.19 +++ pcmcia/cfxga.c 29 Aug 2010 06:27:06 -0000 @@ -319,12 +319,8 @@ cfxga_activate(struct device *dev, int a switch (act) { case DVACT_ACTIVATE: - if (pcmcia_function_enable(sc->sc_pf) != 0) { - printf("%s: function enable failed\n", - sc->sc_dev.dv_xname); - } else { - cfxga_reset_and_repaint(sc); - } + pcmcia_function_enable(sc->sc_pf); + cfxga_reset_and_repaint(sc); break; case DVACT_DEACTIVATE: pcmcia_function_disable(sc->sc_pf); Index: pcmcia/com_pcmcia.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/com_pcmcia.c,v retrieving revision 1.50 diff -u -p -u -r1.50 com_pcmcia.c --- pcmcia/com_pcmcia.c 26 Jun 2010 23:24:45 -0000 1.50 +++ pcmcia/com_pcmcia.c 29 Aug 2010 19:22:48 -0000 @@ -210,22 +210,32 @@ com_pcmcia_activate(dev, act) int act; { struct com_pcmcia_softc *sc = (void *) dev; - int s; - s = spltty(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(sc->sc_pf); sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY, comintr, sc, sc->sc_com.sc_dev.dv_xname); break; - + case DVACT_SUSPEND: + if (sc->sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; + pcmcia_function_disable(sc->sc_pf); + break; + case DVACT_RESUME: + pcmcia_function_enable(sc->sc_pf); + sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY, + comintr, sc, sc->sc_com.sc_dev.dv_xname); + com_resume(&sc->sc_com); + break; case DVACT_DEACTIVATE: - pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + if (sc->sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); break; } - splx(s); return (0); } Index: pcmcia/gpr.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/gpr.c,v retrieving revision 1.14 diff -u -p -u -r1.14 gpr.c --- pcmcia/gpr.c 29 Oct 2009 08:03:16 -0000 1.14 +++ pcmcia/gpr.c 29 Aug 2010 19:22:40 -0000 @@ -247,13 +247,13 @@ gpr_activate(struct device *dev, int act sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY, gpr_intr, sc, sc->sc_dev.dv_xname); break; - case DVACT_DEACTIVATE: - pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + if (sc->sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); break; } - return (0); } Index: pcmcia/if_an_pcmcia.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_an_pcmcia.c,v retrieving revision 1.20 diff -u -p -u -r1.20 if_an_pcmcia.c --- pcmcia/if_an_pcmcia.c 13 Oct 2009 19:33:16 -0000 1.20 +++ pcmcia/if_an_pcmcia.c 29 Aug 2010 19:22:36 -0000 @@ -176,9 +176,7 @@ an_pcmcia_activate(struct device *dev, i struct an_softc *sc = &psc->sc_an; struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; - int s; - s = splnet(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(psc->sc_pf); @@ -186,16 +184,15 @@ an_pcmcia_activate(struct device *dev, i an_intr, sc, sc->sc_dev.dv_xname); an_init(ifp); break; - case DVACT_DEACTIVATE: ifp->if_timer = 0; if (ifp->if_flags & IFF_RUNNING) an_stop(ifp, 1); - pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); + if (sc->sc_ih) + pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; pcmcia_function_disable(psc->sc_pf); break; } - - splx(s); return (0); } Index: pcmcia/if_cnw.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_cnw.c,v retrieving revision 1.20 diff -u -p -u -r1.20 if_cnw.c --- pcmcia/if_cnw.c 13 Oct 2009 19:33:16 -0000 1.20 +++ pcmcia/if_cnw.c 29 Aug 2010 19:22:32 -0000 @@ -860,9 +860,7 @@ cnw_activate(dev, act) { struct cnw_softc *sc = (struct cnw_softc *)dev; struct ifnet *ifp = &sc->sc_arpcom.ac_if; - int s; - s = splnet(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(sc->sc_pf); @@ -870,14 +868,14 @@ cnw_activate(dev, act) cnw_intr, sc, sc->sc_dev.dv_xname); cnw_init(sc); break; - case DVACT_DEACTIVATE: ifp->if_timer = 0; ifp->if_flags &= ~IFF_RUNNING; /* XXX no cnw_stop() ? */ - pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + if (sc->sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); break; } - splx(s); return (0); } Index: pcmcia/if_ep_pcmcia.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_ep_pcmcia.c,v retrieving revision 1.38 diff -u -p -u -r1.38 if_ep_pcmcia.c --- pcmcia/if_ep_pcmcia.c 13 Oct 2009 19:33:16 -0000 1.38 +++ pcmcia/if_ep_pcmcia.c 29 Aug 2010 19:22:26 -0000 @@ -408,26 +408,38 @@ ep_pcmcia_activate(dev, act) struct ep_pcmcia_softc *sc = (struct ep_pcmcia_softc *)dev; struct ep_softc *esc = &sc->sc_ep; struct ifnet *ifp = &esc->sc_arpcom.ac_if; - int s; - s = splnet(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(sc->sc_pf); sc->sc_ep.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, epintr, sc, esc->sc_dev.dv_xname); - epinit(esc); + if (ifp->if_flags & IFF_UP) + epinit(esc); break; - - case DVACT_DEACTIVATE: + case DVACT_SUSPEND: ifp->if_timer = 0; if (ifp->if_flags & IFF_RUNNING) epstop(esc); - pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih); + if (sc->sc_ep.sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih); + sc->sc_ep.sc_ih = NULL; + pcmcia_function_disable(sc->sc_pf); + break; + case DVACT_RESUME: + pcmcia_function_enable(sc->sc_pf); + sc->sc_ep.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, + epintr, sc, esc->sc_dev.dv_xname); + if (ifp->if_flags & IFF_UP) + epinit(esc); + break; + case DVACT_DEACTIVATE: + if (sc->sc_ep.sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih); + sc->sc_ep.sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); break; } - splx(s); return (0); } Index: pcmcia/if_malo.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_malo.c,v retrieving revision 1.70 diff -u -p -u -r1.70 if_malo.c --- pcmcia/if_malo.c 27 Aug 2010 17:08:00 -0000 1.70 +++ pcmcia/if_malo.c 29 Aug 2010 19:22:19 -0000 @@ -29,6 +29,7 @@ #include <sys/malloc.h> #include <sys/sockio.h> #include <sys/mbuf.h> +#include <sys/workq.h> #if NBPFILTER > 0 #include <net/bpf.h> @@ -71,6 +72,7 @@ int malo_pcmcia_match(struct device *, v void malo_pcmcia_attach(struct device *, struct device *, void *); int malo_pcmcia_detach(struct device *, int); int malo_pcmcia_activate(struct device *, int); +void malo_pcmcia_resume(void *, void *); void cmalo_attach(void *); int cmalo_ioctl(struct ifnet *, u_long, caddr_t); @@ -236,30 +238,64 @@ malo_pcmcia_activate(struct device *dev, struct malo_softc *sc = &psc->sc_malo; struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; - int s; - s = splnet(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(psc->sc_pf); psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, cmalo_intr, sc, sc->sc_dev.dv_xname); - cmalo_init(ifp); + workq_queue_task(NULL, &sc->sc_resume_wqt, 0, + malo_pcmcia_resume, sc, NULL); break; - case DVACT_DEACTIVATE: - ifp->if_timer = 0; - if (ifp->if_flags & IFF_RUNNING) + case DVACT_SUSPEND: + if ((sc->sc_flags & MALO_DEVICE_ATTACHED) && + (ifp->if_flags & IFF_RUNNING)) cmalo_stop(sc); - if (psc->sc_ih != NULL) + if (psc->sc_ih) + pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); + psc->sc_ih = NULL; + pcmcia_function_disable(psc->sc_pf); + break; + case DVACT_RESUME: + pcmcia_function_enable(psc->sc_pf); + psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, + cmalo_intr, sc, sc->sc_dev.dv_xname); + workq_queue_task(NULL, &sc->sc_resume_wqt, 0, + malo_pcmcia_resume, sc, NULL); + break; + case DVACT_DEACTIVATE: + if ((sc->sc_flags & MALO_DEVICE_ATTACHED) && + (ifp->if_flags & IFF_RUNNING)) + cmalo_stop(sc); /* XXX tries to touch regs */ + if (psc->sc_ih) pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); + psc->sc_ih = NULL; pcmcia_function_disable(psc->sc_pf); break; } - splx(s); - return (0); } +void +malo_pcmcia_resume(void *arg1, void *arg2) +{ + struct malo_softc *sc = arg1; + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + int s; + + s = splnet(); + while (sc->sc_flags & MALO_BUSY) + tsleep(&sc->sc_flags, 0, "malopwr", 0); + sc->sc_flags |= MALO_BUSY; + + cmalo_init(ifp); + + sc->sc_flags &= ~MALO_BUSY; + wakeup(&sc->sc_flags); + splx(s); +} + /* * Driver. */ @@ -350,6 +386,17 @@ cmalo_ioctl(struct ifnet *ifp, u_long cm int i, j, s, error = 0; s = splnet(); + /* + * Prevent processes from entering this function while another + * process is tsleep'ing in it. + */ + while ((sc->sc_flags & MALO_BUSY) && error == 0) + error = tsleep(&sc->sc_flags, PCATCH, "maloioc", 0); + if (error != 0) { + splx(s); + return error; + } + sc->sc_flags |= MALO_BUSY; switch (cmd) { case SIOCSIFADDR: @@ -430,6 +477,8 @@ cmalo_ioctl(struct ifnet *ifp, u_long cm error = 0; } + sc->sc_flags &= ~MALO_BUSY; + wakeup(&sc->sc_flags); splx(s); return (error); @@ -587,7 +636,7 @@ cmalo_fw_load_main(struct malo_softc *sc for (i = 0; i < bsize / 2; i++) MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i])); MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER); - MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, + MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER); /* poll for an acknowledgement */ @@ -648,8 +697,8 @@ cmalo_init(struct ifnet *ifp) sc->sc_flags &= ~MALO_ASSOC_FAILED; /* get current channel */ - ic->ic_bss->ni_chan = ic->ic_ibss_chan; - sc->sc_curchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); + ic->ic_bss->ni_chan = ic->ic_ibss_chan; + sc->sc_curchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); DPRINTF(1, "%s: current channel is %d\n", sc->sc_dev.dv_xname, sc->sc_curchan); @@ -704,7 +753,7 @@ void cmalo_stop(struct malo_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &ic->ic_if; /* device down */ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); @@ -715,6 +764,7 @@ cmalo_stop(struct malo_softc *sc) /* reset device */ cmalo_cmd_set_reset(sc); sc->sc_flags &= ~MALO_FW_LOADED; + ifp->if_timer = 0; DPRINTF(1, "%s: device down\n", sc->sc_dev.dv_xname); } Index: pcmcia/if_malovar.h =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_malovar.h,v retrieving revision 1.27 diff -u -p -u -r1.27 if_malovar.h --- pcmcia/if_malovar.h 9 Oct 2007 20:37:32 -0000 1.27 +++ pcmcia/if_malovar.h 29 Aug 2010 06:33:54 -0000 @@ -42,7 +42,7 @@ #define MALO_DEVICE_ATTACHED (1 << 0) #define MALO_FW_LOADED (1 << 1) #define MALO_ASSOC_FAILED (1 << 2) - +#define MALO_BUSY (1 << 3) /* * FW command structures */ @@ -365,4 +365,5 @@ struct malo_softc { int sc_net_cur; struct malo_networks sc_net[12]; struct timeout sc_scan_to; + struct workq_task sc_resume_wqt; }; Index: pcmcia/if_ne_pcmcia.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_ne_pcmcia.c,v retrieving revision 1.93 diff -u -p -u -r1.93 if_ne_pcmcia.c --- pcmcia/if_ne_pcmcia.c 13 Oct 2009 19:33:16 -0000 1.93 +++ pcmcia/if_ne_pcmcia.c 29 Aug 2010 19:21:28 -0000 @@ -865,29 +865,47 @@ ne_pcmcia_activate(dev, act) struct ne_pcmcia_softc *sc = (struct ne_pcmcia_softc *)dev; struct dp8390_softc *esc = &sc->sc_ne2000.sc_dp8390; struct ifnet *ifp = &esc->sc_arpcom.ac_if; - int s; - s = splnet(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(sc->sc_pf); sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, dp8390_intr, sc, esc->sc_dev.dv_xname); + /* XXX this is ridiculous */ dp8390_init(esc); + dp8390_stop(esc); break; - - case DVACT_DEACTIVATE: + case DVACT_SUSPEND: ifp->if_timer = 0; - if (ifp->if_flags & IFF_RUNNING) + if (ifp->if_flags & IFF_RUNNING) { dp8390_stop(esc); - if (sc->sc_ih != NULL) { + ifp->if_flags &= ~IFF_RUNNING; + } + if (sc->sc_ih != NULL) pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); - sc->sc_ih = NULL; + sc->sc_ih = NULL; + pcmcia_function_disable(sc->sc_pf); + break; + case DVACT_RESUME: + pcmcia_function_enable(sc->sc_pf); + sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, + dp8390_intr, sc, esc->sc_dev.dv_xname); + dp8390_enable(esc); + if (ifp->if_flags & IFF_UP) + dp8390_init(esc); + break; + case DVACT_DEACTIVATE: + ifp->if_timer = 0; + if (ifp->if_flags & IFF_RUNNING) { + dp8390_stop(esc); + ifp->if_flags &= ~IFF_RUNNING; } + if (sc->sc_ih != NULL) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); break; } - splx(s); return (0); } Index: pcmcia/if_ray.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_ray.c,v retrieving revision 1.42 diff -u -p -u -r1.42 if_ray.c --- pcmcia/if_ray.c 27 Aug 2010 05:04:12 -0000 1.42 +++ pcmcia/if_ray.c 29 Aug 2010 19:22:02 -0000 @@ -654,11 +654,7 @@ ray_activate(struct device *dev, int act { struct ray_softc *sc = (struct ray_softc *)dev; struct ifnet *ifp = &sc->sc_if; - int s; - RAY_DPRINTF(("%s: activate\n", sc->sc_xname)); - - s = splnet(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(sc->sc_pf); @@ -666,18 +662,15 @@ ray_activate(struct device *dev, int act ray_enable(sc); printf("\n"); break; - case DVACT_DEACTIVATE: if (ifp->if_flags & IFF_RUNNING) ray_disable(sc); - if (sc->sc_ih) { + if (sc->sc_ih) pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); - sc->sc_ih = NULL; - } + sc->sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); break; } - splx(s); return (0); } Index: pcmcia/if_sm_pcmcia.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_sm_pcmcia.c,v retrieving revision 1.29 diff -u -p -u -r1.29 if_sm_pcmcia.c --- pcmcia/if_sm_pcmcia.c 13 Oct 2009 19:33:16 -0000 1.29 +++ pcmcia/if_sm_pcmcia.c 29 Aug 2010 19:21:56 -0000 @@ -252,9 +252,7 @@ sm_pcmcia_activate(dev, act) { struct sm_pcmcia_softc *sc = (struct sm_pcmcia_softc *)dev; struct ifnet *ifp = &sc->sc_smc.sc_arpcom.ac_if; - int s; - s = splnet(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(sc->sc_pf); @@ -262,16 +260,16 @@ sm_pcmcia_activate(dev, act) smc91cxx_intr, sc, sc->sc_smc.sc_dev.dv_xname); smc91cxx_init(&sc->sc_smc); break; - case DVACT_DEACTIVATE: ifp->if_timer = 0; if (ifp->if_flags & IFF_RUNNING) smc91cxx_stop(&sc->sc_smc); - pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + if (sc->sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); break; } - splx(s); return (0); } Index: pcmcia/if_wi_pcmcia.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_wi_pcmcia.c,v retrieving revision 1.68 diff -u -p -u -r1.68 if_wi_pcmcia.c --- pcmcia/if_wi_pcmcia.c 13 Oct 2009 19:33:16 -0000 1.68 +++ pcmcia/if_wi_pcmcia.c 29 Aug 2010 19:21:12 -0000 @@ -49,6 +49,7 @@ #include <sys/socket.h> #include <sys/device.h> #include <sys/tree.h> +#include <sys/workq.h> #include <net/if.h> #include <net/if_dl.h> @@ -76,6 +77,7 @@ int wi_pcmcia_match(struct device *, voi void wi_pcmcia_attach(struct device *, struct device *, void *); int wi_pcmcia_detach(struct device *, int); int wi_pcmcia_activate(struct device *, int); +void wi_pcmcia_resume(void *, void *); struct wi_pcmcia_softc { struct wi_softc sc_wi; @@ -83,6 +85,7 @@ struct wi_pcmcia_softc { struct pcmcia_io_handle sc_pcioh; int sc_io_window; struct pcmcia_function *sc_pf; + struct workq_task sc_resume_wqt; }; struct cfattach wi_pcmcia_ca = { @@ -472,28 +475,57 @@ wi_pcmcia_activate(struct device *dev, i struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev; struct wi_softc *sc = &psc->sc_wi; struct ifnet *ifp = &sc->sc_ic.ic_if; - int s; - s = splnet(); switch (act) { case DVACT_ACTIVATE: pcmcia_function_enable(psc->sc_pf); sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, wi_intr, sc, sc->sc_dev.dv_xname); - wi_cor_reset(sc); - wi_init(sc); + workq_queue_task(NULL, &psc->sc_resume_wqt, 0, + wi_pcmcia_resume, sc, NULL); break; - - case DVACT_DEACTIVATE: + case DVACT_SUSPEND: ifp->if_timer = 0; if (ifp->if_flags & IFF_RUNNING) wi_stop(sc); sc->wi_flags &= ~WI_FLAGS_INITIALIZED; if (sc->sc_ih != NULL) pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; + pcmcia_function_disable(psc->sc_pf); + break; + case DVACT_RESUME: + pcmcia_function_enable(psc->sc_pf); + sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, + wi_intr, sc, sc->sc_dev.dv_xname); + workq_queue_task(NULL, &psc->sc_resume_wqt, 0, + wi_pcmcia_resume, sc, NULL); + break; + case DVACT_DEACTIVATE: + if (sc->sc_ih != NULL) + pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; pcmcia_function_disable(psc->sc_pf); break; } - splx(s); return (0); +} + +void +wi_pcmcia_resume(void *arg1, void *arg2) +{ + struct wi_softc *sc = (struct wi_softc *)arg1; + int s; + + s = splnet(); + while (sc->wi_flags & WI_FLAGS_BUSY) + tsleep(&sc->wi_flags, 0, "wipwr", 0); + sc->wi_flags |= WI_FLAGS_BUSY; + + wi_cor_reset(sc); + wi_init(sc); + + sc->wi_flags &= ~WI_FLAGS_BUSY; + wakeup(&sc->wi_flags); + splx(s); } Index: pcmcia/if_xe.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/if_xe.c,v retrieving revision 1.38 diff -u -p -u -r1.38 if_xe.c --- pcmcia/if_xe.c 13 Oct 2009 19:33:16 -0000 1.38 +++ pcmcia/if_xe.c 29 Aug 2010 20:55:01 -0000 @@ -420,11 +420,6 @@ xe_pcmcia_attach(parent, self, aux) ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE); xe_stop(sc); } - -#ifdef notyet - pcmcia_function_disable(pa->pf); -#endif /* notyet */ - return; bad: @@ -466,26 +461,42 @@ xe_pcmcia_activate(dev, act) { struct xe_pcmcia_softc *sc = (struct xe_pcmcia_softc *)dev; struct ifnet *ifp = &sc->sc_xe.sc_arpcom.ac_if; - int s; - s = splnet(); switch (act) { case DVACT_ACTIVATE: + if (sc->sc_xe.sc_ih == NULL) { + pcmcia_function_enable(sc->sc_pf); + sc->sc_xe.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, + xe_intr, sc, sc->sc_xe.sc_dev.dv_xname); + } + break; + case DVACT_SUSPEND: + if (ifp->if_flags & IFF_RUNNING) + xe_stop(&sc->sc_xe); + ifp->if_flags &= ~IFF_RUNNING; + if (sc->sc_xe.sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih); + sc->sc_xe.sc_ih = NULL; + pcmcia_function_disable(sc->sc_pf); + break; + case DVACT_RESUME: pcmcia_function_enable(sc->sc_pf); sc->sc_xe.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, xe_intr, sc, sc->sc_xe.sc_dev.dv_xname); - xe_init(&sc->sc_xe); + /* XXX this is a ridiculous */ + xe_reset(&sc->sc_xe); + if ((ifp->if_flags & IFF_UP) == 0) + xe_stop(&sc->sc_xe); break; - case DVACT_DEACTIVATE: ifp->if_timer = 0; - if (ifp->if_flags & IFF_RUNNING) - xe_stop(&sc->sc_xe); - pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih); + ifp->if_flags &= ~IFF_RUNNING; + if (sc->sc_xe.sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih); + sc->sc_xe.sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); break; } - splx(s); return (0); } Index: pcmcia/pcmcia.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/pcmcia.c,v retrieving revision 1.39 diff -u -p -u -r1.39 pcmcia.c --- pcmcia/pcmcia.c 11 Sep 2007 13:39:34 -0000 1.39 +++ pcmcia/pcmcia.c 29 Aug 2010 18:50:46 -0000 @@ -55,6 +55,7 @@ int pcmcia_verbose = 0; int pcmcia_match(struct device *, void *, void *); int pcmcia_submatch(struct device *, void *, void *); void pcmcia_attach(struct device *, struct device *, void *); +int pcmcia_activate(struct device *, int); int pcmcia_print(void *, const char *); void pcmcia_card_detach_notify(struct device *, void *); void pcmcia_power(int why, void *arg); @@ -71,7 +72,8 @@ struct cfdriver pcmcia_cd = { }; struct cfattach pcmcia_ca = { - sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach + sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach, NULL, + pcmcia_activate }; int @@ -131,31 +133,43 @@ pcmcia_attach(parent, self, aux) powerhook_establish(pcmcia_power, sc); } -void -pcmcia_power(why, arg) - int why; - void *arg; +int +pcmcia_activate(struct device *self, int act) { - struct pcmcia_softc *sc = (struct pcmcia_softc *) arg; + struct pcmcia_softc *sc = (struct pcmcia_softc *)self; struct pcmcia_function *pf; - struct device *d; - int act = DVACT_ACTIVATE; - - if (why != PWR_RESUME) - act = DVACT_DEACTIVATE; - for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; - pf = SIMPLEQ_NEXT(pf, pf_list)) { - if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL) - continue; - d = pf->child; - if (d == NULL) - continue; - if (act == DVACT_ACTIVATE) - config_activate(pf->child); - else + switch (act) { + case DVACT_ACTIVATE: + /* No children yet */ + break; + case DVACT_DEACTIVATE: + for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; + pf = SIMPLEQ_NEXT(pf, pf_list)) { + if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL || + pf->child == NULL) + continue; config_deactivate(pf->child); + } + break; + case DVACT_SUSPEND: + case DVACT_RESUME: + for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; + pf = SIMPLEQ_NEXT(pf, pf_list)) { + if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL || + pf->child == NULL) + continue; + config_suspend(pf->child, act); + } + break; } + return 0; +} + +void +pcmcia_power(int why, void *arg) +{ + pcmcia_activate(arg, why); } int @@ -296,9 +310,8 @@ pcmcia_card_deactivate(dev) */ for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; pf = SIMPLEQ_NEXT(pf, pf_list)) { - if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL) - continue; - if (pf->child == NULL) + if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL || + pf->child == NULL) continue; DPRINTF(("%s: deactivating %s (function %d)\n", sc->dev.dv_xname, pf->child->dv_xname, pf->number)); Index: pcmcia/wdc_pcmcia.c =================================================================== RCS file: /cvs/src/sys/dev/pcmcia/wdc_pcmcia.c,v retrieving revision 1.22 diff -u -p -u -r1.22 wdc_pcmcia.c --- pcmcia/wdc_pcmcia.c 29 Aug 2010 18:41:24 -0000 1.22 +++ pcmcia/wdc_pcmcia.c 29 Aug 2010 20:21:50 -0000 @@ -138,8 +138,6 @@ int wdc_pcmcia_disk_device_interface(str struct wdc_pcmcia_product * wdc_pcmcia_lookup(struct pcmcia_attach_args *); -int wdc_pcmcia_enable(void *, int); - int wdc_pcmcia_disk_device_interface_callback(tuple, arg) struct pcmcia_tuple *tuple; @@ -354,23 +352,12 @@ wdc_pcmcia_attach(parent, self, aux) if (quirks & WDC_PCMCIA_NO_EXTRA_RESETS) sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_EXTRA_RESETS; -#ifdef notyet - /* We can enable and disable the controller. */ - sc->sc_wdcdev.sc_atapi_adapter.scsipi_enable = wdc_pcmcia_enable; - - /* - * Disable the pcmcia function now; wdcattach() will enable - * us again as it adds references to probe for children. - */ - pcmcia_function_disable(pa->pf); -#else /* Establish the interrupt handler. */ sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, wdcintr, &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname); intrstr = pcmcia_intr_string(sc->sc_pf, sc->sc_ih); if (*intrstr) printf(": %s", intrstr); -#endif printf("\n"); @@ -438,81 +425,44 @@ wdc_pcmcia_activate(self, act) int act; { struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self; - int rv = 0, s; + int rv = 0; if (sc->sc_iowindow == -1) /* Nothing to activate/deactivate. */ return (0); - s = splbio(); switch (act) { case DVACT_ACTIVATE: - if (pcmcia_function_enable(sc->sc_pf)) { - printf("%s: couldn't enable PCMCIA function\n", - sc->sc_wdcdev.sc_dev.dv_xname); - rv = EIO; - break; + if (sc->sc_ih == NULL) { + /* XXX attach function already did the work */ + pcmcia_function_enable(sc->sc_pf); + sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, + wdcintr, &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname); + wdcreset(&sc->wdc_channel, VERBOSE); } - + rv = config_activate_children(self, act); + break; + case DVACT_SUSPEND: + rv = config_activate_children(self, act); + if (sc->sc_ih) + pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; + pcmcia_function_disable(sc->sc_pf); + break; + case DVACT_RESUME: + pcmcia_function_enable(sc->sc_pf); sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, wdcintr, &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname); - if (sc->sc_ih == NULL) { - printf("%s: " - "couldn't establish interrupt handler\n", - sc->sc_wdcdev.sc_dev.dv_xname); - pcmcia_function_disable(sc->sc_pf); - rv = EIO; - break; - } - wdcreset(&sc->wdc_channel, VERBOSE); rv = config_activate_children(self, act); break; - case DVACT_DEACTIVATE: - pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); - pcmcia_function_disable(sc->sc_pf); rv = config_activate_children(self, act); - break; - } - splx(s); - return (rv); -} - -#if 0 -int -wdc_pcmcia_enable(arg, onoff) - void *arg; - int onoff; -{ - struct wdc_pcmcia_softc *sc = arg; - - if (onoff) { - if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0) { - if (pcmcia_function_enable(sc->sc_pf)) { - printf("%s: couldn't enable PCMCIA function\n", - sc->sc_wdcdev.sc_dev.dv_xname); - return (EIO); - } - - sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, - wdcintr, &sc->wdc_channel, sc->sc_dev.dv_xname); - if (sc->sc_ih == NULL) { - printf("%s: " - "couldn't establish interrupt handler\n", - sc->sc_wdcdev.sc_dev.dv_xname); - pcmcia_function_disable(sc->sc_pf); - return (EIO); - } - - wdcreset(&sc->wdc_channel, VERBOSE); - } - } else { - if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0) + if (sc->sc_ih) pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); + sc->sc_ih = NULL; pcmcia_function_disable(sc->sc_pf); + break; } - - return (0); + return (rv); } -#endif