summaryrefslogtreecommitdiffstats
path: root/sys/dev/siis/siis.c
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-05-21 17:26:16 +0000
committermav <mav@FreeBSD.org>2010-05-21 17:26:16 +0000
commit2c96d9f1c5d6c4344342edf555576a299c556dd8 (patch)
tree1538757cc83adcb4a8eb2497ade87087f1be984e /sys/dev/siis/siis.c
parentcf780ce2673bbe22eebc547b9fcc51ba023bf5b7 (diff)
downloadFreeBSD-src-2c96d9f1c5d6c4344342edf555576a299c556dd8.zip
FreeBSD-src-2c96d9f1c5d6c4344342edf555576a299c556dd8.tar.gz
Improve suspend/resume support. Make sure controller is idle on suspend
and reset it on resume.
Diffstat (limited to 'sys/dev/siis/siis.c')
-rw-r--r--sys/dev/siis/siis.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/sys/dev/siis/siis.c b/sys/dev/siis/siis.c
index 937d04c..75eb26f 100644
--- a/sys/dev/siis/siis.c
+++ b/sys/dev/siis/siis.c
@@ -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,7 +540,24 @@ siis_ch_detach(device_t dev)
}
static int
-siis_ch_suspend(device_t dev)
+siis_ch_init(device_t dev)
+{
+ struct siis_channel *ch = device_get_softc(dev);
+
+ /* Get port out of reset state. */
+ ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PORT_RESET);
+ ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_32BIT);
+ if (ch->pm_present)
+ ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PME);
+ else
+ ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PME);
+ /* Enable port interrupts */
+ ATA_OUTL(ch->r_mem, SIIS_P_IESET, SIIS_P_IX_ENABLED);
+ return (0);
+}
+
+static int
+siis_ch_deinit(device_t dev)
{
struct siis_channel *ch = device_get_softc(dev);
@@ -548,19 +567,29 @@ siis_ch_suspend(device_t dev)
}
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);
- /* Get port out of reset state. */
- ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PORT_RESET);
- ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_32BIT);
- if (ch->pm_present)
- ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PME);
- else
- ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PME);
- /* Enable port interrupts */
- ATA_OUTL(ch->r_mem, SIIS_P_IESET, SIIS_P_IX_ENABLED);
+ mtx_lock(&ch->mtx);
+ siis_ch_init(dev);
+ siis_reset(dev);
+ xpt_release_simq(ch->sim, TRUE);
+ mtx_unlock(&ch->mtx);
return (0);
}
OpenPOWER on IntegriCloud