From owner-svn-src-all@FreeBSD.ORG Wed Apr 29 21:17:19 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3CD11106564A; Wed, 29 Apr 2009 21:17:19 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 2A2FD8FC27; Wed, 29 Apr 2009 21:17:19 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n3TLHJCV093114; Wed, 29 Apr 2009 21:17:19 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n3TLHIpt093110; Wed, 29 Apr 2009 21:17:18 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <200904292117.n3TLHIpt093110@svn.freebsd.org> From: Alexander Motin Date: Wed, 29 Apr 2009 21:17:18 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r191674 - in head/sys/dev/ata: . chipsets X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 29 Apr 2009 21:17:20 -0000 Author: mav Date: Wed Apr 29 21:17:18 2009 New Revision: 191674 URL: http://svn.freebsd.org/changeset/base/191674 Log: Add experimental support for SATA interface power management. Feature is controlled by hint.ata.X.pm_level tunable: 0 - PM disabled, old behaviour, default. 1 - device is allowed to initiate PM state change, host is passive. 2 - host initiates PARTIAL state transition every time port is idle. 3 - host initiates SLUMBER state transition every time port is idle. PARTIAL state has up to 100us (50us for me) wakeup latency, but for my ICH8M saves 0.5W of power per drive. SLUMBER state has up to 10ms (3.5ms for me) wakeup latency, but saves 0.8W of power. Modes 2 and 3 are implemented only for AHCI driver now. Interface power management is incompatible with device presence detection (host receives no signal from drive, so unable to monitor it), so later is disabled when PM is used. Modified: head/sys/dev/ata/ata-all.h head/sys/dev/ata/ata-pci.c head/sys/dev/ata/ata-sata.c head/sys/dev/ata/chipsets/ata-ahci.c Modified: head/sys/dev/ata/ata-all.h ============================================================================== --- head/sys/dev/ata/ata-all.h Wed Apr 29 21:14:15 2009 (r191673) +++ head/sys/dev/ata/ata-all.h Wed Apr 29 21:17:18 2009 (r191674) @@ -148,9 +148,12 @@ /* SATA AHCI v1.0 register defines */ #define ATA_AHCI_CAP 0x00 -#define ATA_AHCI_NPMASK 0x1f +#define ATA_AHCI_CAP_NPMASK 0x0000001f +#define ATA_AHCI_CAP_PSC 0x00002000 +#define ATA_AHCI_CAP_SSC 0x00004000 #define ATA_AHCI_CAP_SPM 0x00020000 #define ATA_AHCI_CAP_CLO 0x01000000 +#define ATA_AHCI_CAP_SALP 0x04000000 #define ATA_AHCI_CAP_64BIT 0x80000000 #define ATA_AHCI_GHC 0x04 @@ -513,6 +516,7 @@ struct ata_channel { #define ATA_NO_48BIT_DMA 0x08 #define ATA_ALWAYS_DMASTAT 0x10 + int pm_level; /* power management level */ int devices; /* what is present */ #define ATA_ATA_MASTER 0x00000001 #define ATA_ATA_SLAVE 0x00000002 Modified: head/sys/dev/ata/ata-pci.c ============================================================================== --- head/sys/dev/ata/ata-pci.c Wed Apr 29 21:14:15 2009 (r191673) +++ head/sys/dev/ata/ata-pci.c Wed Apr 29 21:17:18 2009 (r191674) @@ -556,6 +556,9 @@ ata_pcichannel_attach(device_t dev) ch->unit = (intptr_t)device_get_ivars(dev); + resource_int_value(device_get_name(dev), + device_get_unit(dev), "pm_level", &ch->pm_level); + if ((error = ctlr->ch_attach(dev))) return error; Modified: head/sys/dev/ata/ata-sata.c ============================================================================== --- head/sys/dev/ata/ata-sata.c Wed Apr 29 21:14:15 2009 (r191673) +++ head/sys/dev/ata/ata-sata.c Wed Apr 29 21:17:18 2009 (r191674) @@ -60,7 +60,7 @@ ata_sata_phy_check_events(device_t dev) ATA_IDX_OUTL(ch, ATA_SERROR, error); /* if we have a connection event deal with it */ - if (error & ATA_SE_PHY_CHANGED) { + if ((error & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) { if (bootverbose) { u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) || @@ -199,9 +199,8 @@ ata_sata_phy_reset(device_t dev, int por ata_udelay(5000); for (loop = 0; loop < 10; loop++) { if (ata_sata_scr_write(ch, port, ATA_SCONTROL, - ATA_SC_DET_IDLE | - ATA_SC_IPM_DIS_PARTIAL | - ATA_SC_IPM_DIS_SLUMBER)) + ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 : + ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))) return (0); ata_udelay(100); if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) Modified: head/sys/dev/ata/chipsets/ata-ahci.c ============================================================================== --- head/sys/dev/ata/chipsets/ata-ahci.c Wed Apr 29 21:14:15 2009 (r191673) +++ head/sys/dev/ata/chipsets/ata-ahci.c Wed Apr 29 21:17:18 2009 (r191674) @@ -131,7 +131,7 @@ ata_ahci_chipinit(device_t dev) ctlr->ichannels = ATA_INL(ctlr->r_res2, ATA_AHCI_PI); ctlr->channels = MAX(flsl(ctlr->ichannels), - (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1); + (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_NPMASK) + 1); ctlr->reset = ata_ahci_reset; ctlr->ch_attach = ata_ahci_ch_attach; @@ -148,7 +148,7 @@ ata_ahci_chipinit(device_t dev) "AHCI Version %x%x.%x%x controller with %d ports PM %s\n", (version >> 24) & 0xff, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff, - (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1, + (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_NPMASK) + 1, (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) ? "supported" : "not supported"); return 0; @@ -286,7 +286,9 @@ ata_ahci_ch_resume(device_t dev) /* activate the channel and power/spin up device */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, - (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD)); + (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | + ((ch->pm_level > 1) ? ATA_AHCI_P_CMD_ALPE : 0) | + ((ch->pm_level > 2) ? ATA_AHCI_P_CMD_ASP : 0 ))); ata_ahci_start_fr(dev); ata_ahci_start(dev); @@ -818,9 +820,9 @@ ata_ahci_reset(device_t dev) ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | - ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP | - ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS | - ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); + ((ch->pm_level == 0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) | + ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | + ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); /* only probe for PortMultiplier if HW has support */ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) {