diff options
author | iwasaki <iwasaki@FreeBSD.org> | 2001-11-23 14:27:33 +0000 |
---|---|---|
committer | iwasaki <iwasaki@FreeBSD.org> | 2001-11-23 14:27:33 +0000 |
commit | 22f1a1787832ee6a4a43eefe50ac3a0326b31cf0 (patch) | |
tree | 79a8d24898e282aa59714d7958d2ce3620946b64 /sys/pci | |
parent | a518818140f3c6a5b953804575447786ef53c09a (diff) | |
download | FreeBSD-src-22f1a1787832ee6a4a43eefe50ac3a0326b31cf0.zip FreeBSD-src-22f1a1787832ee6a4a43eefe50ac3a0326b31cf0.tar.gz |
Add suspend/resume code mostly merged from fxp driver.
Diffstat (limited to 'sys/pci')
-rw-r--r-- | sys/pci/if_rl.c | 72 | ||||
-rw-r--r-- | sys/pci/if_rlreg.h | 7 |
2 files changed, 79 insertions, 0 deletions
diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c index 3502f20..bc92a00 100644 --- a/sys/pci/if_rl.c +++ b/sys/pci/if_rl.c @@ -170,6 +170,8 @@ static int rl_ioctl __P((struct ifnet *, u_long, caddr_t)); static void rl_init __P((void *)); static void rl_stop __P((struct rl_softc *)); static void rl_watchdog __P((struct ifnet *)); +static int rl_suspend __P((device_t)); +static int rl_resume __P((device_t)); static void rl_shutdown __P((device_t)); static int rl_ifmedia_upd __P((struct ifnet *)); static void rl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); @@ -210,6 +212,8 @@ static device_method_t rl_methods[] = { DEVMETHOD(device_probe, rl_probe), DEVMETHOD(device_attach, rl_attach), DEVMETHOD(device_detach, rl_detach), + DEVMETHOD(device_suspend, rl_suspend), + DEVMETHOD(device_resume, rl_resume), DEVMETHOD(device_shutdown, rl_shutdown), /* bus interface */ @@ -1345,6 +1349,11 @@ static void rl_intr(arg) u_int16_t status; sc = arg; + + if (sc->suspended) { + return; + } + RL_LOCK(sc); ifp = &sc->arpcom.ac_if; @@ -1746,6 +1755,69 @@ static void rl_stop(sc) } /* + * Device suspend routine. Stop the interface and save some PCI + * settings in case the BIOS doesn't restore them properly on + * resume. + */ +static int rl_suspend(dev) + device_t dev; +{ + register int i; + struct rl_softc *sc; + + sc = device_get_softc(dev); + + rl_stop(sc); + + for (i = 0; i < 5; i++) + sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4); + sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); + sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); + sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); + sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); + + sc->suspended = 1; + + return (0); +} + +/* + * Device resume routine. Restore some PCI settings in case the BIOS + * doesn't, re-enable busmastering, and restart the interface if + * appropriate. + */ +static int rl_resume(dev) + device_t dev; +{ + register int i; + struct rl_softc *sc; + struct ifnet *ifp; + + sc = device_get_softc(dev); + ifp = &sc->arpcom.ac_if; + + /* better way to do this? */ + for (i = 0; i < 5; i++) + pci_write_config(dev, PCIR_MAPS + i * 4, sc->saved_maps[i], 4); + pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); + pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); + pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); + pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); + + /* reenable busmastering */ + pci_enable_busmaster(dev); + pci_enable_io(dev, RL_RES); + + /* reinitialize interface if necessary */ + if (ifp->if_flags & IFF_UP) + rl_init(sc); + + sc->suspended = 0; + + return (0); +} + +/* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h index aecc83d..4342eb6 100644 --- a/sys/pci/if_rlreg.h +++ b/sys/pci/if_rlreg.h @@ -377,6 +377,13 @@ struct rl_softc { struct rl_chain_data rl_cdata; struct callout_handle rl_stat_ch; struct mtx rl_mtx; + int suspended; /* 0 = normal 1 = suspended */ + + u_int32_t saved_maps[5]; /* pci data */ + u_int32_t saved_biosaddr; + u_int8_t saved_intline; + u_int8_t saved_cachelnsz; + u_int8_t saved_lattimer; }; #define RL_LOCK(_sc) mtx_lock(&(_sc)->rl_mtx) |