diff options
author | mav <mav@FreeBSD.org> | 2010-05-21 17:26:16 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2010-05-21 17:26:16 +0000 |
commit | 2c96d9f1c5d6c4344342edf555576a299c556dd8 (patch) | |
tree | 1538757cc83adcb4a8eb2497ade87087f1be984e /sys/dev/siis | |
parent | cf780ce2673bbe22eebc547b9fcc51ba023bf5b7 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/dev/siis/siis.c | 53 |
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); } |