mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
MFC r208375, r208393:
Improve suspend/resume support. Make sure controller is idle on suspend and reset it on resume.
This commit is contained in:
parent
541246310d
commit
6488c6b3e9
4 changed files with 154 additions and 56 deletions
|
|
@ -60,6 +60,8 @@ static void ahci_intr(void *data);
|
|||
static void ahci_intr_one(void *data);
|
||||
static int ahci_suspend(device_t dev);
|
||||
static int ahci_resume(device_t dev);
|
||||
static int ahci_ch_init(device_t dev);
|
||||
static int ahci_ch_deinit(device_t dev);
|
||||
static int ahci_ch_suspend(device_t dev);
|
||||
static int ahci_ch_resume(device_t dev);
|
||||
static void ahci_ch_pm(void *arg);
|
||||
|
|
@ -871,7 +873,7 @@ ahci_ch_attach(device_t dev)
|
|||
return (ENXIO);
|
||||
ahci_dmainit(dev);
|
||||
ahci_slotsalloc(dev);
|
||||
ahci_ch_resume(dev);
|
||||
ahci_ch_init(dev);
|
||||
mtx_lock(&ch->mtx);
|
||||
rid = ATA_IRQ_RID;
|
||||
if (!(ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
|
||||
|
|
@ -963,7 +965,7 @@ ahci_ch_detach(device_t dev)
|
|||
bus_teardown_intr(dev, ch->r_irq, ch->ih);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
|
||||
|
||||
ahci_ch_suspend(dev);
|
||||
ahci_ch_deinit(dev);
|
||||
ahci_slotsfree(dev);
|
||||
ahci_dmafini(dev);
|
||||
|
||||
|
|
@ -973,28 +975,7 @@ ahci_ch_detach(device_t dev)
|
|||
}
|
||||
|
||||
static int
|
||||
ahci_ch_suspend(device_t dev)
|
||||
{
|
||||
struct ahci_channel *ch = device_get_softc(dev);
|
||||
|
||||
/* Disable port interrupts. */
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_IE, 0);
|
||||
/* Reset command register. */
|
||||
ahci_stop(dev);
|
||||
ahci_stop_fr(dev);
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_CMD, 0);
|
||||
/* Allow everything, including partial and slumber modes. */
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_SCTL, 0);
|
||||
/* Request slumber mode transition and give some time to get there. */
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_CMD, AHCI_P_CMD_SLUMBER);
|
||||
DELAY(100);
|
||||
/* Disable PHY. */
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_SCTL, ATA_SC_DET_DISABLE);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ahci_ch_resume(device_t dev)
|
||||
ahci_ch_init(device_t dev)
|
||||
{
|
||||
struct ahci_channel *ch = device_get_softc(dev);
|
||||
uint64_t work;
|
||||
|
|
@ -1018,6 +999,54 @@ ahci_ch_resume(device_t dev)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ahci_ch_deinit(device_t dev)
|
||||
{
|
||||
struct ahci_channel *ch = device_get_softc(dev);
|
||||
|
||||
/* Disable port interrupts. */
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_IE, 0);
|
||||
/* Reset command register. */
|
||||
ahci_stop(dev);
|
||||
ahci_stop_fr(dev);
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_CMD, 0);
|
||||
/* Allow everything, including partial and slumber modes. */
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_SCTL, 0);
|
||||
/* Request slumber mode transition and give some time to get there. */
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_CMD, AHCI_P_CMD_SLUMBER);
|
||||
DELAY(100);
|
||||
/* Disable PHY. */
|
||||
ATA_OUTL(ch->r_mem, AHCI_P_SCTL, ATA_SC_DET_DISABLE);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ahci_ch_suspend(device_t dev)
|
||||
{
|
||||
struct ahci_channel *ch = device_get_softc(dev);
|
||||
|
||||
mtx_lock(&ch->mtx);
|
||||
xpt_freeze_simq(ch->sim, 1);
|
||||
while (ch->oslots)
|
||||
msleep(ch, &ch->mtx, PRIBIO, "ahcisusp", hz/100);
|
||||
ahci_ch_deinit(dev);
|
||||
mtx_unlock(&ch->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ahci_ch_resume(device_t dev)
|
||||
{
|
||||
struct ahci_channel *ch = device_get_softc(dev);
|
||||
|
||||
mtx_lock(&ch->mtx);
|
||||
ahci_ch_init(dev);
|
||||
ahci_reset(dev);
|
||||
xpt_release_simq(ch->sim, TRUE);
|
||||
mtx_unlock(&ch->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
devclass_t ahcich_devclass;
|
||||
static device_method_t ahcich_methods[] = {
|
||||
DEVMETHOD(device_probe, ahci_ch_probe),
|
||||
|
|
|
|||
|
|
@ -432,7 +432,13 @@ ata_suspend(device_t dev)
|
|||
if (!dev || !(ch = device_get_softc(dev)))
|
||||
return ENXIO;
|
||||
|
||||
#ifndef ATA_CAM
|
||||
#ifdef ATA_CAM
|
||||
mtx_lock(&ch->state_mtx);
|
||||
xpt_freeze_simq(ch->sim, 1);
|
||||
while (ch->state != ATA_IDLE)
|
||||
msleep(ch, &ch->state_mtx, PRIBIO, "atasusp", hz/100);
|
||||
mtx_unlock(&ch->state_mtx);
|
||||
#else
|
||||
/* wait for the channel to be IDLE or detached before suspending */
|
||||
while (ch->r_irq) {
|
||||
mtx_lock(&ch->state_mtx);
|
||||
|
|
@ -452,16 +458,21 @@ ata_suspend(device_t dev)
|
|||
int
|
||||
ata_resume(device_t dev)
|
||||
{
|
||||
struct ata_channel *ch;
|
||||
int error;
|
||||
|
||||
/* check for valid device */
|
||||
if (!dev || !device_get_softc(dev))
|
||||
if (!dev || !(ch = device_get_softc(dev)))
|
||||
return ENXIO;
|
||||
|
||||
#ifdef ATA_CAM
|
||||
mtx_lock(&ch->state_mtx);
|
||||
error = ata_reinit(dev);
|
||||
xpt_release_simq(ch->sim, TRUE);
|
||||
mtx_unlock(&ch->state_mtx);
|
||||
#else
|
||||
/* reinit the devices, we dont know what mode/state they are in */
|
||||
error = ata_reinit(dev);
|
||||
|
||||
#ifndef ATA_CAM
|
||||
/* kick off requests on the queue */
|
||||
ata_start(dev);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ __FBSDID("$FreeBSD$");
|
|||
#include <cam/cam_debug.h>
|
||||
|
||||
/* local prototypes */
|
||||
static int mvs_ch_init(device_t dev);
|
||||
static int mvs_ch_deinit(device_t dev);
|
||||
static int mvs_ch_suspend(device_t dev);
|
||||
static int mvs_ch_resume(device_t dev);
|
||||
static void mvs_dmainit(device_t dev);
|
||||
|
|
@ -133,7 +135,7 @@ mvs_ch_attach(device_t dev)
|
|||
return (ENXIO);
|
||||
mvs_dmainit(dev);
|
||||
mvs_slotsalloc(dev);
|
||||
mvs_ch_resume(dev);
|
||||
mvs_ch_init(dev);
|
||||
mtx_lock(&ch->mtx);
|
||||
rid = ATA_IRQ_RID;
|
||||
if (!(ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
|
||||
|
|
@ -215,7 +217,7 @@ mvs_ch_detach(device_t dev)
|
|||
bus_teardown_intr(dev, ch->r_irq, ch->ih);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
|
||||
|
||||
mvs_ch_suspend(dev);
|
||||
mvs_ch_deinit(dev);
|
||||
mvs_slotsfree(dev);
|
||||
mvs_dmafini(dev);
|
||||
|
||||
|
|
@ -225,19 +227,7 @@ mvs_ch_detach(device_t dev)
|
|||
}
|
||||
|
||||
static int
|
||||
mvs_ch_suspend(device_t dev)
|
||||
{
|
||||
struct mvs_channel *ch = device_get_softc(dev);
|
||||
|
||||
/* Stop EDMA */
|
||||
mvs_set_edma_mode(dev, MVS_EDMA_OFF);
|
||||
/* Disable port interrupts. */
|
||||
ATA_OUTL(ch->r_mem, EDMA_IEM, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mvs_ch_resume(device_t dev)
|
||||
mvs_ch_init(device_t dev)
|
||||
{
|
||||
struct mvs_channel *ch = device_get_softc(dev);
|
||||
uint32_t reg;
|
||||
|
|
@ -264,6 +254,45 @@ mvs_ch_resume(device_t dev)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mvs_ch_deinit(device_t dev)
|
||||
{
|
||||
struct mvs_channel *ch = device_get_softc(dev);
|
||||
|
||||
/* Stop EDMA */
|
||||
mvs_set_edma_mode(dev, MVS_EDMA_OFF);
|
||||
/* Disable port interrupts. */
|
||||
ATA_OUTL(ch->r_mem, EDMA_IEM, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mvs_ch_suspend(device_t dev)
|
||||
{
|
||||
struct mvs_channel *ch = device_get_softc(dev);
|
||||
|
||||
mtx_lock(&ch->mtx);
|
||||
xpt_freeze_simq(ch->sim, 1);
|
||||
while (ch->oslots)
|
||||
msleep(ch, &ch->mtx, PRIBIO, "mvssusp", hz/100);
|
||||
mvs_ch_deinit(dev);
|
||||
mtx_unlock(&ch->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mvs_ch_resume(device_t dev)
|
||||
{
|
||||
struct mvs_channel *ch = device_get_softc(dev);
|
||||
|
||||
mtx_lock(&ch->mtx);
|
||||
mvs_ch_init(dev);
|
||||
mvs_reset(dev);
|
||||
xpt_release_simq(ch->sim, TRUE);
|
||||
mtx_unlock(&ch->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct mvs_dc_cb_args {
|
||||
bus_addr_t maddr;
|
||||
int error;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ static int siis_setup_interrupt(device_t dev);
|
|||
static void siis_intr(void *data);
|
||||
static int siis_suspend(device_t dev);
|
||||
static int siis_resume(device_t dev);
|
||||
static int siis_ch_init(device_t dev);
|
||||
static int siis_ch_deinit(device_t dev);
|
||||
static int siis_ch_suspend(device_t dev);
|
||||
static int siis_ch_resume(device_t dev);
|
||||
static void siis_ch_intr_locked(void *data);
|
||||
|
|
@ -458,7 +460,7 @@ siis_ch_attach(device_t dev)
|
|||
return (ENXIO);
|
||||
siis_dmainit(dev);
|
||||
siis_slotsalloc(dev);
|
||||
siis_ch_resume(dev);
|
||||
siis_ch_init(dev);
|
||||
mtx_lock(&ch->mtx);
|
||||
rid = ATA_IRQ_RID;
|
||||
if (!(ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
|
||||
|
|
@ -528,7 +530,7 @@ siis_ch_detach(device_t dev)
|
|||
bus_teardown_intr(dev, ch->r_irq, ch->ih);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
|
||||
|
||||
siis_ch_suspend(dev);
|
||||
siis_ch_deinit(dev);
|
||||
siis_slotsfree(dev);
|
||||
siis_dmafini(dev);
|
||||
|
||||
|
|
@ -538,17 +540,7 @@ siis_ch_detach(device_t dev)
|
|||
}
|
||||
|
||||
static int
|
||||
siis_ch_suspend(device_t dev)
|
||||
{
|
||||
struct siis_channel *ch = device_get_softc(dev);
|
||||
|
||||
/* Put port into reset state. */
|
||||
ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PORT_RESET);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
siis_ch_resume(device_t dev)
|
||||
siis_ch_init(device_t dev)
|
||||
{
|
||||
struct siis_channel *ch = device_get_softc(dev);
|
||||
|
||||
|
|
@ -564,6 +556,43 @@ siis_ch_resume(device_t dev)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
siis_ch_deinit(device_t dev)
|
||||
{
|
||||
struct siis_channel *ch = device_get_softc(dev);
|
||||
|
||||
/* Put port into reset state. */
|
||||
ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PORT_RESET);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
siis_ch_suspend(device_t dev)
|
||||
{
|
||||
struct siis_channel *ch = device_get_softc(dev);
|
||||
|
||||
mtx_lock(&ch->mtx);
|
||||
xpt_freeze_simq(ch->sim, 1);
|
||||
while (ch->oslots)
|
||||
msleep(ch, &ch->mtx, PRIBIO, "siissusp", hz/100);
|
||||
siis_ch_deinit(dev);
|
||||
mtx_unlock(&ch->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
siis_ch_resume(device_t dev)
|
||||
{
|
||||
struct siis_channel *ch = device_get_softc(dev);
|
||||
|
||||
mtx_lock(&ch->mtx);
|
||||
siis_ch_init(dev);
|
||||
siis_reset(dev);
|
||||
xpt_release_simq(ch->sim, TRUE);
|
||||
mtx_unlock(&ch->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
devclass_t siisch_devclass;
|
||||
static device_method_t siisch_methods[] = {
|
||||
DEVMETHOD(device_probe, siis_ch_probe),
|
||||
|
|
|
|||
Loading…
Reference in a new issue