summaryrefslogtreecommitdiffstats
path: root/sys/dev/dc
diff options
context:
space:
mode:
authoriwasaki <iwasaki@FreeBSD.org>2002-05-06 10:55:42 +0000
committeriwasaki <iwasaki@FreeBSD.org>2002-05-06 10:55:42 +0000
commitf42381b21e451afd59bae8a0d8456750f5f2131c (patch)
tree4ed59412ea566f5aa2db0a4f4b2ecd5d7a672d78 /sys/dev/dc
parent18274834278cef77879f1074640e4b4ce93416ee (diff)
downloadFreeBSD-src-f42381b21e451afd59bae8a0d8456750f5f2131c.zip
FreeBSD-src-f42381b21e451afd59bae8a0d8456750f5f2131c.tar.gz
Add suspend/resume code mostly merged from fxp/rl driver.
This is temporary hack, better and generalized solution probably should be implemented at lower layer(MII or PCI?). Tested by: shoko.araki@soliton.co.jp MFC after: 1 week
Diffstat (limited to 'sys/dev/dc')
-rw-r--r--sys/dev/dc/if_dc.c81
-rw-r--r--sys/dev/dc/if_dcreg.h7
2 files changed, 88 insertions, 0 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
index 8deb27e..189835c 100644
--- a/sys/dev/dc/if_dc.c
+++ b/sys/dev/dc/if_dc.c
@@ -198,6 +198,8 @@ static struct dc_type dc_devs[] = {
static int dc_probe (device_t);
static int dc_attach (device_t);
static int dc_detach (device_t);
+static int dc_suspend (device_t);
+static int dc_resume (device_t);
static void dc_acpi (device_t);
static struct dc_type *dc_devtype (device_t);
static int dc_newbuf (struct dc_softc *, int, struct mbuf *);
@@ -273,6 +275,8 @@ static device_method_t dc_methods[] = {
DEVMETHOD(device_probe, dc_probe),
DEVMETHOD(device_attach, dc_attach),
DEVMETHOD(device_detach, dc_detach),
+ DEVMETHOD(device_suspend, dc_suspend),
+ DEVMETHOD(device_resume, dc_resume),
DEVMETHOD(device_shutdown, dc_shutdown),
/* bus interface */
@@ -2871,6 +2875,10 @@ static void dc_intr(arg)
sc = arg;
+ if (sc->suspended) {
+ return;
+ }
+
if ((CSR_READ_4(sc, DC_ISR) & DC_INTRS) == 0)
return;
@@ -3522,6 +3530,79 @@ static void dc_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 dc_suspend(dev)
+ device_t dev;
+{
+ register int i;
+ int s;
+ struct dc_softc *sc;
+
+ s = splimp();
+
+ sc = device_get_softc(dev);
+
+ dc_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;
+
+ splx(s);
+ 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 dc_resume(dev)
+ device_t dev;
+{
+ register int i;
+ int s;
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+
+ s = splimp();
+
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ dc_acpi(dev);
+
+ /* 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, DC_RES);
+
+ /* reinitialize interface if necessary */
+ if (ifp->if_flags & IFF_UP)
+ dc_init(sc);
+
+ sc->suspended = 0;
+
+ splx(s);
+ 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/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h
index 46bd3c3..5c0879a 100644
--- a/sys/dev/dc/if_dcreg.h
+++ b/sys/dev/dc/if_dcreg.h
@@ -726,6 +726,13 @@ struct dc_softc {
#ifdef DEVICE_POLLING
int rxcycles; /* ... when polling */
#endif
+ 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;
};
OpenPOWER on IntegriCloud