Improve suspend/resume support. Make sure controller is idle on suspend

and reset it on resume.
This commit is contained in:
Alexander Motin 2010-05-21 17:26:16 +00:00
parent e826ef1ec4
commit 243e0fb9a0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=208393
2 changed files with 86 additions and 28 deletions

View File

@ -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;

View File

@ -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),