From f42381b21e451afd59bae8a0d8456750f5f2131c Mon Sep 17 00:00:00 2001 From: iwasaki Date: Mon, 6 May 2002 10:55:42 +0000 Subject: 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 --- sys/dev/dc/if_dc.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ sys/dev/dc/if_dcreg.h | 7 +++++ sys/pci/if_dc.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ sys/pci/if_dcreg.h | 7 +++++ 4 files changed, 176 insertions(+) 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; }; diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c index 8deb27e..189835c 100644 --- a/sys/pci/if_dc.c +++ b/sys/pci/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/pci/if_dcreg.h b/sys/pci/if_dcreg.h index 46bd3c3..5c0879a 100644 --- a/sys/pci/if_dcreg.h +++ b/sys/pci/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; }; -- cgit v1.1