mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-13 10:02:38 +00:00
Added support for APM suspend/resume.
PR: 18756 Submitted by: mike ryan <msr@elision.org>, with modifications by me.
This commit is contained in:
parent
87807fded9
commit
7dced78a28
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=66007
@ -221,6 +221,7 @@ static int fxp_mediachange __P((struct ifnet *));
|
||||
static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
|
||||
static void fxp_set_media __P((struct fxp_softc *, int));
|
||||
static __inline void fxp_scb_wait __P((struct fxp_softc *));
|
||||
static __inline void fxp_dma_wait __P((volatile u_int16_t *, struct fxp_softc *sc));
|
||||
static FXP_INTR_TYPE fxp_intr __P((void *));
|
||||
static void fxp_start __P((struct ifnet *));
|
||||
static int fxp_ioctl __P((struct ifnet *,
|
||||
@ -290,7 +291,23 @@ fxp_scb_wait(sc)
|
||||
{
|
||||
int i = 10000;
|
||||
|
||||
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
|
||||
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i)
|
||||
DELAY(2);
|
||||
if (i == 0)
|
||||
printf(FXP_FORMAT ": SCB timeout\n", FXP_ARGS(sc));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
fxp_dma_wait(status, sc)
|
||||
volatile u_int16_t *status;
|
||||
struct fxp_softc *sc;
|
||||
{
|
||||
int i = 10000;
|
||||
|
||||
while (!(*status & FXP_CB_STATUS_C) && --i)
|
||||
DELAY(2);
|
||||
if (i == 0)
|
||||
printf(FXP_FORMAT ": DMA timeout\n", FXP_ARGS(sc));
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
@ -687,12 +704,85 @@ fxp_shutdown(device_t dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device suspend routine. Stop the interface and save some PCI
|
||||
* settings in case the BIOS doesn't restore them properly on
|
||||
* resume.
|
||||
*/
|
||||
static int
|
||||
fxp_suspend(device_t dev)
|
||||
{
|
||||
struct fxp_softc *sc = device_get_softc(dev);
|
||||
int i, s;
|
||||
|
||||
s = splimp();
|
||||
|
||||
fxp_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
|
||||
fxp_resume(device_t dev)
|
||||
{
|
||||
struct fxp_softc *sc = device_get_softc(dev);
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
u_int16_t pci_command;
|
||||
int i, s;
|
||||
|
||||
s = splimp();
|
||||
|
||||
/* 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_command = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
pci_command |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
|
||||
pci_write_config(dev, PCIR_COMMAND, pci_command, 2);
|
||||
|
||||
CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
|
||||
DELAY(10);
|
||||
|
||||
/* reinitialize interface if necessary */
|
||||
if (ifp->if_flags & IFF_UP)
|
||||
fxp_init(sc);
|
||||
|
||||
sc->suspended = 0;
|
||||
|
||||
splx(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static device_method_t fxp_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, fxp_probe),
|
||||
DEVMETHOD(device_attach, fxp_attach),
|
||||
DEVMETHOD(device_detach, fxp_detach),
|
||||
DEVMETHOD(device_shutdown, fxp_shutdown),
|
||||
DEVMETHOD(device_suspend, fxp_suspend),
|
||||
DEVMETHOD(device_resume, fxp_resume),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
@ -1126,7 +1216,7 @@ fxp_intr(arg)
|
||||
FXP_LOCK(sc, s);
|
||||
#endif
|
||||
|
||||
while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
|
||||
while (!sc->suspended && (statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
|
||||
#if defined(__NetBSD__)
|
||||
claimed = 1;
|
||||
#endif
|
||||
@ -1364,6 +1454,9 @@ fxp_stop(sc)
|
||||
FXP_LOCK(sc, s);
|
||||
#endif
|
||||
|
||||
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
|
||||
ifp->if_timer = 0;
|
||||
|
||||
/*
|
||||
* Cancel stats updater.
|
||||
*/
|
||||
@ -1407,8 +1500,6 @@ fxp_stop(sc)
|
||||
}
|
||||
}
|
||||
|
||||
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
|
||||
ifp->if_timer = 0;
|
||||
#if !defined(__NetBSD__)
|
||||
FXP_UNLOCK(sc, s);
|
||||
#endif
|
||||
@ -1526,7 +1617,7 @@ fxp_init(xsc)
|
||||
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||
/* ...and wait for it to complete. */
|
||||
while (!(cbp->cb_status & FXP_CB_STATUS_C));
|
||||
fxp_dma_wait(&cbp->cb_status, sc);
|
||||
|
||||
/*
|
||||
* Now initialize the station address. Temporarily use the TxCB
|
||||
@ -1550,7 +1641,7 @@ fxp_init(xsc)
|
||||
fxp_scb_wait(sc);
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||
/* ...and wait for it to complete. */
|
||||
while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
|
||||
fxp_dma_wait(&cb_ias->cb_status, sc);
|
||||
|
||||
/*
|
||||
* Initialize transmit control block (TxCB) list.
|
||||
@ -1990,6 +2081,7 @@ fxp_mc_setup(sc)
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
struct ifmultiaddr *ifma;
|
||||
int nmcasts;
|
||||
int count;
|
||||
|
||||
/*
|
||||
* If there are queued commands, we must wait until they are all
|
||||
@ -2072,8 +2164,14 @@ fxp_mc_setup(sc)
|
||||
* Wait until command unit is not active. This should never
|
||||
* be the case when nothing is queued, but make sure anyway.
|
||||
*/
|
||||
count = 100;
|
||||
while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
|
||||
FXP_SCB_CUS_ACTIVE) ;
|
||||
FXP_SCB_CUS_ACTIVE && --count)
|
||||
DELAY(10);
|
||||
if (count == 0) {
|
||||
printf(FXP_FORMAT ": command queue timeout\n", FXP_ARGS(sc));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the multicast setup command.
|
||||
|
@ -69,6 +69,12 @@ struct fxp_softc {
|
||||
int phy_primary_device; /* device type of primary PHY */
|
||||
int phy_10Mbps_only; /* PHY is 10Mbps-only device */
|
||||
int eeprom_size; /* size of serial EEPROM */
|
||||
int suspended; /* 0 = normal 1 = suspended (APM) */
|
||||
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;
|
||||
};
|
||||
|
||||
/* Macros to ease CSR access. */
|
||||
|
112
sys/pci/if_fxp.c
112
sys/pci/if_fxp.c
@ -221,6 +221,7 @@ static int fxp_mediachange __P((struct ifnet *));
|
||||
static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
|
||||
static void fxp_set_media __P((struct fxp_softc *, int));
|
||||
static __inline void fxp_scb_wait __P((struct fxp_softc *));
|
||||
static __inline void fxp_dma_wait __P((volatile u_int16_t *, struct fxp_softc *sc));
|
||||
static FXP_INTR_TYPE fxp_intr __P((void *));
|
||||
static void fxp_start __P((struct ifnet *));
|
||||
static int fxp_ioctl __P((struct ifnet *,
|
||||
@ -290,7 +291,23 @@ fxp_scb_wait(sc)
|
||||
{
|
||||
int i = 10000;
|
||||
|
||||
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
|
||||
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i)
|
||||
DELAY(2);
|
||||
if (i == 0)
|
||||
printf(FXP_FORMAT ": SCB timeout\n", FXP_ARGS(sc));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
fxp_dma_wait(status, sc)
|
||||
volatile u_int16_t *status;
|
||||
struct fxp_softc *sc;
|
||||
{
|
||||
int i = 10000;
|
||||
|
||||
while (!(*status & FXP_CB_STATUS_C) && --i)
|
||||
DELAY(2);
|
||||
if (i == 0)
|
||||
printf(FXP_FORMAT ": DMA timeout\n", FXP_ARGS(sc));
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
@ -687,12 +704,85 @@ fxp_shutdown(device_t dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device suspend routine. Stop the interface and save some PCI
|
||||
* settings in case the BIOS doesn't restore them properly on
|
||||
* resume.
|
||||
*/
|
||||
static int
|
||||
fxp_suspend(device_t dev)
|
||||
{
|
||||
struct fxp_softc *sc = device_get_softc(dev);
|
||||
int i, s;
|
||||
|
||||
s = splimp();
|
||||
|
||||
fxp_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
|
||||
fxp_resume(device_t dev)
|
||||
{
|
||||
struct fxp_softc *sc = device_get_softc(dev);
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
u_int16_t pci_command;
|
||||
int i, s;
|
||||
|
||||
s = splimp();
|
||||
|
||||
/* 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_command = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
pci_command |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
|
||||
pci_write_config(dev, PCIR_COMMAND, pci_command, 2);
|
||||
|
||||
CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
|
||||
DELAY(10);
|
||||
|
||||
/* reinitialize interface if necessary */
|
||||
if (ifp->if_flags & IFF_UP)
|
||||
fxp_init(sc);
|
||||
|
||||
sc->suspended = 0;
|
||||
|
||||
splx(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static device_method_t fxp_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, fxp_probe),
|
||||
DEVMETHOD(device_attach, fxp_attach),
|
||||
DEVMETHOD(device_detach, fxp_detach),
|
||||
DEVMETHOD(device_shutdown, fxp_shutdown),
|
||||
DEVMETHOD(device_suspend, fxp_suspend),
|
||||
DEVMETHOD(device_resume, fxp_resume),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
@ -1126,7 +1216,7 @@ fxp_intr(arg)
|
||||
FXP_LOCK(sc, s);
|
||||
#endif
|
||||
|
||||
while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
|
||||
while (!sc->suspended && (statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
|
||||
#if defined(__NetBSD__)
|
||||
claimed = 1;
|
||||
#endif
|
||||
@ -1364,6 +1454,9 @@ fxp_stop(sc)
|
||||
FXP_LOCK(sc, s);
|
||||
#endif
|
||||
|
||||
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
|
||||
ifp->if_timer = 0;
|
||||
|
||||
/*
|
||||
* Cancel stats updater.
|
||||
*/
|
||||
@ -1407,8 +1500,6 @@ fxp_stop(sc)
|
||||
}
|
||||
}
|
||||
|
||||
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
|
||||
ifp->if_timer = 0;
|
||||
#if !defined(__NetBSD__)
|
||||
FXP_UNLOCK(sc, s);
|
||||
#endif
|
||||
@ -1526,7 +1617,7 @@ fxp_init(xsc)
|
||||
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||
/* ...and wait for it to complete. */
|
||||
while (!(cbp->cb_status & FXP_CB_STATUS_C));
|
||||
fxp_dma_wait(&cbp->cb_status, sc);
|
||||
|
||||
/*
|
||||
* Now initialize the station address. Temporarily use the TxCB
|
||||
@ -1550,7 +1641,7 @@ fxp_init(xsc)
|
||||
fxp_scb_wait(sc);
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||
/* ...and wait for it to complete. */
|
||||
while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
|
||||
fxp_dma_wait(&cb_ias->cb_status, sc);
|
||||
|
||||
/*
|
||||
* Initialize transmit control block (TxCB) list.
|
||||
@ -1990,6 +2081,7 @@ fxp_mc_setup(sc)
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
struct ifmultiaddr *ifma;
|
||||
int nmcasts;
|
||||
int count;
|
||||
|
||||
/*
|
||||
* If there are queued commands, we must wait until they are all
|
||||
@ -2072,8 +2164,14 @@ fxp_mc_setup(sc)
|
||||
* Wait until command unit is not active. This should never
|
||||
* be the case when nothing is queued, but make sure anyway.
|
||||
*/
|
||||
count = 100;
|
||||
while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
|
||||
FXP_SCB_CUS_ACTIVE) ;
|
||||
FXP_SCB_CUS_ACTIVE && --count)
|
||||
DELAY(10);
|
||||
if (count == 0) {
|
||||
printf(FXP_FORMAT ": command queue timeout\n", FXP_ARGS(sc));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the multicast setup command.
|
||||
|
@ -69,6 +69,12 @@ struct fxp_softc {
|
||||
int phy_primary_device; /* device type of primary PHY */
|
||||
int phy_10Mbps_only; /* PHY is 10Mbps-only device */
|
||||
int eeprom_size; /* size of serial EEPROM */
|
||||
int suspended; /* 0 = normal 1 = suspended (APM) */
|
||||
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;
|
||||
};
|
||||
|
||||
/* Macros to ease CSR access. */
|
||||
|
Loading…
Reference in New Issue
Block a user