summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_rl.c
diff options
context:
space:
mode:
authoriwasaki <iwasaki@FreeBSD.org>2001-11-23 14:27:33 +0000
committeriwasaki <iwasaki@FreeBSD.org>2001-11-23 14:27:33 +0000
commit22f1a1787832ee6a4a43eefe50ac3a0326b31cf0 (patch)
tree79a8d24898e282aa59714d7958d2ce3620946b64 /sys/pci/if_rl.c
parenta518818140f3c6a5b953804575447786ef53c09a (diff)
downloadFreeBSD-src-22f1a1787832ee6a4a43eefe50ac3a0326b31cf0.zip
FreeBSD-src-22f1a1787832ee6a4a43eefe50ac3a0326b31cf0.tar.gz
Add suspend/resume code mostly merged from fxp driver.
Diffstat (limited to 'sys/pci/if_rl.c')
-rw-r--r--sys/pci/if_rl.c72
1 files changed, 72 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.
*/
OpenPOWER on IntegriCloud