summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2009-02-20 23:17:52 +0000
committermav <mav@FreeBSD.org>2009-02-20 23:17:52 +0000
commit1348b6bf738e7990a24a05eab5a61e17345549eb (patch)
treecb80049d47d553241be761a98116510b58b2954e /sys/dev/ata
parent6b0a7363d7b12ba8ed8a5555063e5d62b0b8365c (diff)
downloadFreeBSD-src-1348b6bf738e7990a24a05eab5a61e17345549eb.zip
FreeBSD-src-1348b6bf738e7990a24a05eab5a61e17345549eb.tar.gz
Disable port hardware on detach. First switch it to slumber mode to
power-down peer transmitter, then disable completely. Side effect of this is saving about 0.5W of power per detached device.
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/chipsets/ata-ahci.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c
index a950793..9dd2488 100644
--- a/sys/dev/ata/chipsets/ata-ahci.c
+++ b/sys/dev/ata/chipsets/ata-ahci.c
@@ -230,6 +230,22 @@ ata_ahci_ch_attach(device_t dev)
int
ata_ahci_ch_detach(device_t dev)
{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset = ch->unit << 7;
+
+ /* Disable port interrupts. */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0);
+ /* Reset command register. */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, 0);
+
+ /* Allow everything including partial and slumber modes. */
+ ATA_IDX_OUTL(ch, ATA_SCONTROL, 0);
+ /* Request slumber mode transition and give some time to get there. */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SLUMBER);
+ DELAY(100);
+ /* Disable PHY. */
+ ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_DISABLE);
ata_dmafini(dev);
return (0);
OpenPOWER on IntegriCloud