add suspend/resume support for PCI ral(4) devices.
authordamien <damien@openbsd.org>
Wed, 4 Aug 2010 19:48:33 +0000 (19:48 +0000)
committerdamien <damien@openbsd.org>
Wed, 4 Aug 2010 19:48:33 +0000 (19:48 +0000)
ok deraadt@, sthen@

tested by matthew@ (RT2560), dcoppa@ (RT2790), okan@ (RT2860), todd@ (RT2560)

sys/dev/ic/rt2560.c
sys/dev/ic/rt2560var.h
sys/dev/ic/rt2661.c
sys/dev/ic/rt2661var.h
sys/dev/ic/rt2860.c
sys/dev/ic/rt2860var.h
sys/dev/pci/if_ral_pci.c

index 634eb1c..5149908 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rt2560.c,v 1.48 2010/05/19 15:27:35 oga Exp $  */
+/*     $OpenBSD: rt2560.c,v 1.49 2010/08/04 19:48:33 damien Exp $  */
 
 /*-
  * Copyright (c) 2005, 2006
@@ -334,6 +334,24 @@ rt2560_detach(void *xsc)
        return 0;
 }
 
+void
+rt2560_suspend(void *xsc)
+{
+       struct rt2560_softc *sc = xsc;
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
+
+       if (ifp->if_flags & IFF_RUNNING)
+               rt2560_stop(ifp, 0);
+}
+
+void
+rt2560_resume(void *xsc)
+{
+       struct rt2560_softc *sc = xsc;
+
+       rt2560_power(PWR_RESUME, sc);
+}
+
 int
 rt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring,
     int count)
@@ -2717,13 +2735,11 @@ rt2560_power(int why, void *arg)
        struct ifnet *ifp = &sc->sc_ic.ic_if;
        int s;
 
-       DPRINTF(("%s: rt2560_power(%d)\n", sc->sc_dev.dv_xname, why));
-
        s = splnet();
        switch (why) {
        case PWR_SUSPEND:
        case PWR_STANDBY:
-               rt2560_stop(ifp, 1);
+               rt2560_stop(ifp, 0);
                if (sc->sc_power != NULL)
                        (*sc->sc_power)(sc, why);
                break;
@@ -2732,8 +2748,6 @@ rt2560_power(int why, void *arg)
                        rt2560_init(ifp);
                        if (sc->sc_power != NULL)
                                (*sc->sc_power)(sc, why);
-                       if (ifp->if_flags & IFF_RUNNING)
-                               rt2560_start(ifp);
                }
                break;
        }
index e269508..d6b9432 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rt2560var.h,v 1.6 2009/08/10 17:47:23 damien Exp $  */
+/*     $OpenBSD: rt2560var.h,v 1.7 2010/08/04 19:48:33 damien Exp $  */
 
 /*-
  * Copyright (c) 2005, 2006
@@ -167,4 +167,6 @@ struct rt2560_softc {
 
 int    rt2560_attach(void *, int);
 int    rt2560_detach(void *);
+void   rt2560_suspend(void *);
+void   rt2560_resume(void *);
 int    rt2560_intr(void *);
index b9ce6f0..ca351be 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rt2661.c,v 1.54 2010/05/19 15:27:35 oga Exp $ */
+/*     $OpenBSD: rt2661.c,v 1.55 2010/08/04 19:48:33 damien Exp $      */
 
 /*-
  * Copyright (c) 2006
@@ -74,6 +74,7 @@ int rt2661_debug = 1;
 #define DPRINTFN(n, x)
 #endif
 
+void           rt2661_attachhook(void *);
 int            rt2661_alloc_tx_ring(struct rt2661_softc *,
                    struct rt2661_tx_ring *, int);
 void           rt2661_reset_tx_ring(struct rt2661_softc *,
@@ -144,8 +145,7 @@ void                rt2661_read_eeprom(struct rt2661_softc *);
 int            rt2661_bbp_init(struct rt2661_softc *);
 int            rt2661_init(struct ifnet *);
 void           rt2661_stop(struct ifnet *, int);
-int            rt2661_load_microcode(struct rt2661_softc *, const uint8_t *,
-                   int);
+int            rt2661_load_microcode(struct rt2661_softc *);
 void           rt2661_rx_tune(struct rt2661_softc *);
 #ifdef notyet
 void           rt2661_radar_start(struct rt2661_softc *);
@@ -186,9 +186,8 @@ rt2661_attach(void *xsc, int id)
 {
        struct rt2661_softc *sc = xsc;
        struct ieee80211com *ic = &sc->sc_ic;
-       struct ifnet *ifp = &ic->ic_if;
        uint32_t val;
-       int error, ac, i, ntries;
+       int error, ac, ntries;
 
        sc->sc_id = id;
 
@@ -243,6 +242,51 @@ rt2661_attach(void *xsc, int id)
                goto fail2;
        }
 
+       if (rootvp == NULL)
+               mountroothook_establish(rt2661_attachhook, sc);
+       else
+               rt2661_attachhook(sc);
+
+       sc->sc_powerhook = powerhook_establish(rt2661_power, sc);
+       if (sc->sc_powerhook == NULL) {
+               printf("%s: WARNING: unable to establish power hook\n",
+                   sc->sc_dev.dv_xname);
+       }
+
+       return 0;
+
+fail2: rt2661_free_tx_ring(sc, &sc->mgtq);
+fail1: while (--ac >= 0)
+               rt2661_free_tx_ring(sc, &sc->txq[ac]);
+       return ENXIO;
+}
+
+void
+rt2661_attachhook(void *xsc)
+{
+       struct rt2661_softc *sc = xsc;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       const char *name = NULL;        /* make lint happy */
+       int i, error;
+
+       switch (sc->sc_id) {
+       case PCI_PRODUCT_RALINK_RT2561:
+               name = "ral-rt2561";
+               break;
+       case PCI_PRODUCT_RALINK_RT2561S:
+               name = "ral-rt2561s";
+               break;
+       case PCI_PRODUCT_RALINK_RT2661:
+               name = "ral-rt2661";
+               break;
+       }
+       if ((error = loadfirmware(name, &sc->ucode, &sc->ucsize)) != 0) {
+               printf("%s: error %d, could not read firmware %s\n",
+                   sc->sc_dev.dv_xname, error, name);
+               return;
+       }
+
        ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
        ic->ic_state = IEEE80211_S_INIT;
@@ -328,19 +372,6 @@ rt2661_attach(void *xsc, int id)
        sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
        sc->sc_txtap.wt_ihdr.it_present = htole32(RT2661_TX_RADIOTAP_PRESENT);
 #endif
-
-       sc->sc_powerhook = powerhook_establish(rt2661_power, sc);
-       if (sc->sc_powerhook == NULL) {
-               printf("%s: WARNING: unable to establish power hook\n",
-                   sc->sc_dev.dv_xname);
-       }
-
-       return 0;
-
-fail2: rt2661_free_tx_ring(sc, &sc->mgtq);
-fail1: while (--ac >= 0)
-               rt2661_free_tx_ring(sc, &sc->txq[ac]);
-       return ENXIO;
 }
 
 int
@@ -364,9 +395,30 @@ rt2661_detach(void *xsc)
        rt2661_free_tx_ring(sc, &sc->mgtq);
        rt2661_free_rx_ring(sc, &sc->rxq);
 
+       if (sc->ucode != NULL)
+               free(sc->ucode, M_DEVBUF);
+
        return 0;
 }
 
+void
+rt2661_suspend(void *xsc)
+{
+       struct rt2661_softc *sc = xsc;
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
+
+       if (ifp->if_flags & IFF_RUNNING)
+               rt2661_stop(ifp, 0);
+}
+
+void
+rt2661_resume(void *xsc)
+{
+       struct rt2661_softc *sc = xsc;
+
+       rt2661_power(PWR_RESUME, sc);
+}
+
 int
 rt2661_alloc_tx_ring(struct rt2661_softc *sc, struct rt2661_tx_ring *ring,
     int count)
@@ -2404,11 +2456,8 @@ rt2661_init(struct ifnet *ifp)
 {
        struct rt2661_softc *sc = ifp->if_softc;
        struct ieee80211com *ic = &sc->sc_ic;
-       const char *name = NULL;        /* make lint happy */
-       uint8_t *ucode;
-       size_t size;
        uint32_t tmp, sta[3];
-       int i, ntries, error;
+       int i, ntries;
 
        /* for CardBus, power on the socket */
        if (!(sc->sc_flags & RT2661_ENABLED)) {
@@ -2422,36 +2471,11 @@ rt2661_init(struct ifnet *ifp)
 
        rt2661_stop(ifp, 0);
 
-       if (!(sc->sc_flags & RT2661_FWLOADED)) {
-               switch (sc->sc_id) {
-               case PCI_PRODUCT_RALINK_RT2561:
-                       name = "ral-rt2561";
-                       break;
-               case PCI_PRODUCT_RALINK_RT2561S:
-                       name = "ral-rt2561s";
-                       break;
-               case PCI_PRODUCT_RALINK_RT2661:
-                       name = "ral-rt2661";
-                       break;
-               }
-
-               if ((error = loadfirmware(name, &ucode, &size)) != 0) {
-                       printf("%s: error %d, could not read firmware %s\n",
-                           sc->sc_dev.dv_xname, error, name);
-                       rt2661_stop(ifp, 1);
-                       return EIO;
-               }
-
-               if (rt2661_load_microcode(sc, ucode, size) != 0) {
-                       printf("%s: could not load 8051 microcode\n",
-                           sc->sc_dev.dv_xname);
-                       free(ucode, M_DEVBUF);
-                       rt2661_stop(ifp, 1);
-                       return EIO;
-               }
-
-               free(ucode, M_DEVBUF);
-               sc->sc_flags |= RT2661_FWLOADED;
+       if (rt2661_load_microcode(sc) != 0) {
+               printf("%s: could not load 8051 microcode\n",
+                   sc->sc_dev.dv_xname);
+               rt2661_stop(ifp, 1);
+               return EIO;
        }
 
        /* initialize Tx rings */
@@ -2614,13 +2638,13 @@ rt2661_stop(struct ifnet *ifp, int disable)
        if (disable && sc->sc_disable != NULL) {
                if (sc->sc_flags & RT2661_ENABLED) {
                        (*sc->sc_disable)(sc);
-                       sc->sc_flags &= ~(RT2661_ENABLED | RT2661_FWLOADED);
+                       sc->sc_flags &= ~RT2661_ENABLED;
                }
        }
 }
 
 int
-rt2661_load_microcode(struct rt2661_softc *sc, const uint8_t *ucode, int size)
+rt2661_load_microcode(struct rt2661_softc *sc)
 {
        int ntries;
 
@@ -2634,7 +2658,7 @@ rt2661_load_microcode(struct rt2661_softc *sc, const uint8_t *ucode, int size)
 
        /* write 8051's microcode */
        RAL_WRITE(sc, RT2661_MCU_CNTL_CSR, RT2661_MCU_RESET | RT2661_MCU_SEL);
-       RAL_WRITE_REGION_1(sc, RT2661_MCU_CODE_BASE, ucode, size);
+       RAL_WRITE_REGION_1(sc, RT2661_MCU_CODE_BASE, sc->ucode, sc->ucsize);
        RAL_WRITE(sc, RT2661_MCU_CNTL_CSR, RT2661_MCU_RESET);
 
        /* kick 8051's ass */
@@ -2906,14 +2930,11 @@ rt2661_power(int why, void *arg)
        struct ifnet *ifp = &sc->sc_ic.ic_if;
        int s;
 
-       DPRINTF(("%s: rt2661_power(%d)\n", sc->sc_dev.dv_xname, why));
-
        s = splnet();
        switch (why) {
        case PWR_SUSPEND:
        case PWR_STANDBY:
-               rt2661_stop(ifp, 1);
-               sc->sc_flags &= ~RT2661_FWLOADED; 
+               rt2661_stop(ifp, 0);
                if (sc->sc_power != NULL)
                        (*sc->sc_power)(sc, why);
                break;
@@ -2922,8 +2943,6 @@ rt2661_power(int why, void *arg)
                        rt2661_init(ifp);       
                        if (sc->sc_power != NULL)
                                (*sc->sc_power)(sc, why);
-                       if (ifp->if_flags & IFF_RUNNING)
-                               rt2661_start(ifp);
                }
                break;
        }
index 7793ade..b426a8b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rt2661var.h,v 1.10 2009/08/10 17:47:23 damien Exp $   */
+/*     $OpenBSD: rt2661var.h,v 1.11 2010/08/04 19:48:33 damien Exp $   */
 
 /*-
  * Copyright (c) 2006
@@ -109,14 +109,16 @@ struct rt2661_softc {
        int                             sc_id;
        int                             sc_flags;
 #define RT2661_ENABLED         (1 << 0)
-#define RT2661_FWLOADED                (1 << 1)
-#define RT2661_UPDATE_SLOT     (1 << 2)
-#define RT2661_SET_SLOTTIME    (1 << 3)
+#define RT2661_UPDATE_SLOT     (1 << 1)
+#define RT2661_SET_SLOTTIME    (1 << 2)
 
        int                             sc_tx_timer;
 
        struct ieee80211_channel        *sc_curchan;
 
+       u_char                          *ucode;
+       size_t                          ucsize;
+
        uint8_t                         rf_rev;
 
        uint8_t                         rfprog;
@@ -178,4 +180,6 @@ struct rt2661_softc {
 
 int    rt2661_attach(void *, int);
 int    rt2661_detach(void *);
+void   rt2661_suspend(void *);
+void   rt2661_resume(void *);
 int    rt2661_intr(void *);
index 88ecaa7..25b6a78 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rt2860.c,v 1.56 2010/07/19 19:47:52 damien Exp $      */
+/*     $OpenBSD: rt2860.c,v 1.57 2010/08/04 19:48:33 damien Exp $      */
 
 /*-
  * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -78,6 +78,7 @@ int rt2860_debug = 0;
 #define DPRINTFN(n, x)
 #endif
 
+void           rt2860_attachhook(void *);
 int            rt2860_alloc_tx_ring(struct rt2860_softc *,
                    struct rt2860_tx_ring *);
 void           rt2860_reset_tx_ring(struct rt2860_softc *,
@@ -206,8 +207,7 @@ rt2860_attach(void *xsc, int id)
 {
        struct rt2860_softc *sc = xsc;
        struct ieee80211com *ic = &sc->sc_ic;
-       struct ifnet *ifp = &ic->ic_if;
-       int i, qid, ntries, error;
+       int qid, ntries, error;
        uint32_t tmp;
 
        sc->amrr.amrr_min_success_threshold =  1;
@@ -272,6 +272,40 @@ rt2860_attach(void *xsc, int id)
        sc->mgtqid = (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) ?
            EDCA_AC_VO : 5;
 
+       if (rootvp == NULL)
+               mountroothook_establish(rt2860_attachhook, sc);
+       else
+               rt2860_attachhook(sc);
+
+       sc->sc_powerhook = powerhook_establish(rt2860_power, sc);
+       if (sc->sc_powerhook == NULL) {
+               printf("%s: WARNING: unable to establish power hook\n",
+                   sc->sc_dev.dv_xname);
+       }
+
+       return 0;
+
+fail2: rt2860_free_rx_ring(sc, &sc->rxq);
+fail1: while (--qid >= 0)
+               rt2860_free_tx_ring(sc, &sc->txq[qid]);
+       return error;
+}
+
+void
+rt2860_attachhook(void *xsc)
+{
+       struct rt2860_softc *sc = xsc;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       int i, error;
+
+       error = loadfirmware("ral-rt2860", &sc->ucode, &sc->ucsize);
+       if (error != 0) {
+               printf("%s: error %d, could not read firmware file %s\n",
+                   sc->sc_dev.dv_xname, error, "ral-rt2860");
+               return;
+       }
+
        ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
        ic->ic_state = IEEE80211_S_INIT;
@@ -362,19 +396,6 @@ rt2860_attach(void *xsc, int id)
        sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
        sc->sc_txtap.wt_ihdr.it_present = htole32(RT2860_TX_RADIOTAP_PRESENT);
 #endif
-
-       sc->sc_powerhook = powerhook_establish(rt2860_power, sc);
-       if (sc->sc_powerhook == NULL) {
-               printf("%s: WARNING: unable to establish power hook\n",
-                   sc->sc_dev.dv_xname);
-       }
-
-       return 0;
-
-fail2: rt2860_free_rx_ring(sc, &sc->rxq);
-fail1: while (--qid >= 0)
-               rt2860_free_tx_ring(sc, &sc->txq[qid]);
-       return error;
 }
 
 int
@@ -395,9 +416,30 @@ rt2860_detach(void *xsc)
        rt2860_free_rx_ring(sc, &sc->rxq);
        rt2860_free_tx_pool(sc);
 
+       if (sc->ucode != NULL)
+               free(sc->ucode, M_DEVBUF);
+
        return 0;
 }
 
+void
+rt2860_suspend(void *xsc)
+{
+       struct rt2860_softc *sc = xsc;
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
+
+       if (ifp->if_flags & IFF_RUNNING)
+               rt2860_stop(ifp, 0);
+}
+
+void
+rt2860_resume(void *xsc)
+{
+       struct rt2860_softc *sc = xsc;
+
+       rt2860_power(PWR_RESUME, sc);
+}
+
 int
 rt2860_alloc_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
 {
@@ -3340,14 +3382,11 @@ rt2860_init(struct ifnet *ifp)
        RAL_BARRIER_WRITE(sc);
        RAL_WRITE(sc, RT2860_SYS_CTRL, 0xe00);
 
-       if (!(sc->sc_flags & RT2860_FWLOADED)) {
-               if ((error = rt2860_load_microcode(sc)) != 0) {
-                       printf("%s: could not load 8051 microcode\n",
-                           sc->sc_dev.dv_xname);
-                       rt2860_stop(ifp, 1);
-                       return error;
-               }
-               sc->sc_flags |= RT2860_FWLOADED;
+       if ((error = rt2860_load_microcode(sc)) != 0) {
+               printf("%s: could not load 8051 microcode\n",
+                   sc->sc_dev.dv_xname);
+               rt2860_stop(ifp, 1);
+               return error;
        }
 
        IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
@@ -3620,7 +3659,7 @@ rt2860_stop(struct ifnet *ifp, int disable)
        if (disable && sc->sc_disable != NULL) {
                if (sc->sc_flags & RT2860_ENABLED) {
                        (*sc->sc_disable)(sc);
-                       sc->sc_flags &= ~(RT2860_ENABLED | RT2860_FWLOADED);
+                       sc->sc_flags &= ~RT2860_ENABLED;
                }
        }
 }
@@ -3628,20 +3667,12 @@ rt2860_stop(struct ifnet *ifp, int disable)
 int
 rt2860_load_microcode(struct rt2860_softc *sc)
 {
-       u_char *ucode;
-       size_t size;
-       int error, ntries;
-
-       if ((error = loadfirmware("ral-rt2860", &ucode, &size)) != 0) {
-               printf("%s: error %d, could not read firmware file %s\n",
-                   sc->sc_dev.dv_xname, error, "ral-rt2860");
-               return error;
-       }
+       int ntries;
 
        /* set "host program ram write selection" bit */
        RAL_WRITE(sc, RT2860_SYS_CTRL, RT2860_HST_PM_SEL);
        /* write microcode image */
-       RAL_WRITE_REGION_1(sc, RT2860_FW_BASE, ucode, size);
+       RAL_WRITE_REGION_1(sc, RT2860_FW_BASE, sc->ucode, sc->ucsize);
        /* kick microcontroller unit */
        RAL_WRITE(sc, RT2860_SYS_CTRL, 0);
        RAL_BARRIER_WRITE(sc);
@@ -3650,8 +3681,6 @@ rt2860_load_microcode(struct rt2860_softc *sc)
        RAL_WRITE(sc, RT2860_H2M_BBPAGENT, 0);
        RAL_WRITE(sc, RT2860_H2M_MAILBOX, 0);
 
-       free(ucode, M_DEVBUF);
-
        /* wait until microcontroller is ready */
        RAL_BARRIER_READ_WRITE(sc);
        for (ntries = 0; ntries < 1000; ntries++) {
@@ -3845,8 +3874,7 @@ rt2860_power(int why, void *arg)
        switch (why) {
        case PWR_SUSPEND:
        case PWR_STANDBY:
-               rt2860_stop(ifp, 1);
-               sc->sc_flags &= ~RT2860_FWLOADED;
+               rt2860_stop(ifp, 0);
                if (sc->sc_power != NULL)
                        (*sc->sc_power)(sc, why);
                break;
@@ -3855,8 +3883,6 @@ rt2860_power(int why, void *arg)
                        rt2860_init(ifp);
                        if (sc->sc_power != NULL)
                                (*sc->sc_power)(sc, why);
-                       if (ifp->if_flags & IFF_RUNNING)
-                               rt2860_start(ifp);
                }
                break;
        }
index 1fd4a04..5a1b538 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rt2860var.h,v 1.17 2010/07/19 19:47:52 damien Exp $   */
+/*     $OpenBSD: rt2860var.h,v 1.18 2010/08/04 19:48:33 damien Exp $   */
 
 /*-
  * Copyright (c) 2007
@@ -123,13 +123,15 @@ struct rt2860_softc {
 
        int                             sc_flags;
 #define RT2860_ENABLED         (1 << 0)
-#define RT2860_FWLOADED                (1 << 1)
-#define RT2860_ADVANCED_PS     (1 << 2)
-#define RT2860_PCIE            (1 << 3)
+#define RT2860_ADVANCED_PS     (1 << 1)
+#define RT2860_PCIE            (1 << 2)
 
        uint32_t                        sc_ic_flags;
        int                             fixed_ridx;
 
+       u_char                          *ucode;
+       size_t                          ucsize;
+
        struct rt2860_tx_ring           txq[6];
        struct rt2860_rx_ring           rxq;
 
@@ -202,4 +204,6 @@ struct rt2860_softc {
 
 int    rt2860_attach(void *, int);
 int    rt2860_detach(void *);
+void   rt2860_suspend(void *);
+void   rt2860_resume(void *);
 int    rt2860_intr(void *);
index ac1eaae..795c3cb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_ral_pci.c,v 1.19 2010/04/05 14:14:02 damien Exp $  */
+/*     $OpenBSD: if_ral_pci.c,v 1.20 2010/08/04 19:48:33 damien Exp $  */
 
 /*-
  * Copyright (c) 2005-2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -31,6 +31,7 @@
 #include <sys/malloc.h>
 #include <sys/timeout.h>
 #include <sys/device.h>
+#include <sys/workq.h>
 
 #include <machine/bus.h>
 #include <machine/intr.h>
 static struct ral_opns {
        int     (*attach)(void *, int);
        int     (*detach)(void *);
+       void    (*suspend)(void *);
+       void    (*resume)(void *);
        int     (*intr)(void *);
 
 }  ral_rt2560_opns = {
        rt2560_attach,
        rt2560_detach,
+       rt2560_suspend,
+       rt2560_resume,
        rt2560_intr
 
 }, ral_rt2661_opns = {
        rt2661_attach,
        rt2661_detach,
+       rt2661_suspend,
+       rt2661_resume,
        rt2661_intr
 
 }, ral_rt2860_opns = {
        rt2860_attach,
        rt2860_detach,
+       rt2860_suspend,
+       rt2860_resume,
        rt2860_intr
 };
 
@@ -88,6 +97,7 @@ struct ral_pci_softc {
        pci_chipset_tag_t       sc_pc;
        void                    *sc_ih;
        bus_size_t              sc_mapsize;
+       struct workq_task       sc_resume_wqt;
 };
 
 /* Base Address Register */
@@ -96,10 +106,12 @@ struct ral_pci_softc {
 int    ral_pci_match(struct device *, void *, void *);
 void   ral_pci_attach(struct device *, struct device *, void *);
 int    ral_pci_detach(struct device *, int);
+int    ral_pci_activate(struct device *, int);
+void   ral_pci_resume(void *, void *);
 
 struct cfattach ral_pci_ca = {
        sizeof (struct ral_pci_softc), ral_pci_match, ral_pci_attach,
-       ral_pci_detach
+       ral_pci_detach, ral_pci_activate
 };
 
 const struct pci_matchid ral_pci_devices[] = {
@@ -216,3 +228,34 @@ ral_pci_detach(struct device *self, int flags)
 
        return 0;
 }
+
+int
+ral_pci_activate(struct device *self, int act)
+{
+       struct ral_pci_softc *psc = (struct ral_pci_softc *)self;
+       struct rt2560_softc *sc = &psc->sc_sc;
+
+       switch (act) {
+       case DVACT_SUSPEND:
+               (*psc->sc_opns->suspend)(sc);
+               break;
+       case DVACT_RESUME:
+               workq_queue_task(NULL, &psc->sc_resume_wqt, 0,
+                   ral_pci_resume, psc, NULL);
+               break;
+       }
+
+       return 0;
+}
+
+void
+ral_pci_resume(void *arg1, void *arg2)
+{
+       struct ral_pci_softc *psc = arg1;
+       struct rt2560_softc *sc = &psc->sc_sc;
+       int s;
+
+       s = splnet();
+       (*psc->sc_opns->resume)(sc);
+       splx(s);
+}