From: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
To: jeff@garzik.org
Cc: linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org,
linux-kernel@vger.kernel.org, htejun@gmail.com,
Kristen Carlson Accardi <kristen.c.accardi@intel.com>,
arjan@linux.intel.com
Subject: [patch 3/3] Enable Aggressive Link Power management for AHCI controllers.
Date: Wed, 20 Jun 2007 14:23:42 -0700 [thread overview]
Message-ID: <20070620142342.404856fe.kristen.c.accardi@intel.com> (raw)
In-Reply-To: <20070611184146.448266229@intel.com>
Enable Aggressive Link Power management for AHCI controllers.
This patch will set the correct bits to turn on Aggressive
Link Power Management (ALPM) for the ahci driver. This
will cause the controller and disk to negotiate a lower
power state for the link when there is no activity (see
the AHCI 1.x spec for details). This feature is mutually
exclusive with Hot Plug, so when ALPM is enabled, Hot Plug
is disabled. ALPM will be enabled by default, but it is
settable via the scsi host syfs interface. Possible
settings for this feature are:
Setting Effect
----------------------------------------------------------
min_power ALPM is enabled, and link set to enter
lowest power state (SLUMBER) when idle
Hot plug not allowed.
max_performance ALPM is disabled, Hot Plug is allowed
medium_power ALPM is enabled, and link set to enter
second lowest power state (PARTIAL) when
idle. Hot plug not allowed.
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
---
I've changed this patch to define "disable_pm", and to change
the behavior of ahci_disable_alpm() to not change the link
pm policy, and just turn off alpm.
this whole patch series can be found here:
http://www.kernel.org/pub/linux/kernel/people/kristen/patches/SATA/alpm/
Index: 2.6-git/drivers/ata/ahci.c
===================================================================
--- 2.6-git.orig/drivers/ata/ahci.c
+++ 2.6-git/drivers/ata/ahci.c
@@ -48,6 +48,9 @@
#define DRV_NAME "ahci"
#define DRV_VERSION "2.2"
+static int ahci_enable_alpm(struct ata_port *ap,
+ enum scsi_host_link_pm policy);
+static int ahci_disable_alpm(struct ata_port *ap);
enum {
AHCI_PCI_BAR = 5,
@@ -97,6 +100,7 @@ enum {
/* HOST_CAP bits */
HOST_CAP_SSC = (1 << 14), /* Slumber capable */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
@@ -151,6 +155,8 @@ enum {
PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
/* PORT_CMD bits */
+ PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */
+ PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
@@ -171,6 +177,7 @@ enum {
AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */
AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */
+ AHCI_FLAG_NO_HOTPLUG = (1 << 29), /* ignore PxSERR.DIAG.N */
AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
@@ -253,6 +260,7 @@ static struct scsi_host_template ahci_sh
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .set_link_pm_policy = ata_scsi_set_link_pm_policy,
};
static const struct ata_port_operations ahci_ops = {
@@ -284,6 +292,8 @@ static const struct ata_port_operations
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
#endif
+ .enable_pm = ahci_enable_alpm,
+ .disable_pm = ahci_disable_alpm,
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
@@ -719,6 +729,158 @@ static void ahci_power_up(struct ata_por
writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
}
+static int ahci_disable_alpm(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd, scontrol;
+ struct ahci_port_priv *pp = ap->private_data;
+
+ /*
+ * disable Interface Power Management State Transitions
+ * This is accomplished by setting bits 8:11 of the
+ * SATA Control register
+ */
+ scontrol = readl(port_mmio + PORT_SCR_CTL);
+ scontrol |= (0x3 << 8);
+ writel(scontrol, port_mmio + PORT_SCR_CTL);
+
+ /* get the existing command bits */
+ cmd = readl(port_mmio + PORT_CMD);
+
+ /* disable ALPM and ASP */
+ cmd &= ~PORT_CMD_ASP;
+ cmd &= ~PORT_CMD_ALPE;
+
+ /* force the interface back to active */
+ cmd |= PORT_CMD_ICC_ACTIVE;
+
+ /* write out new cmd value */
+ writel(cmd, port_mmio + PORT_CMD);
+ cmd = readl(port_mmio + PORT_CMD);
+
+ /* wait 10ms to be sure we've come out of any low power state */
+ msleep(10);
+
+ /* clear out any PhyRdy stuff from interrupt status */
+ writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
+
+ /* go ahead and clean out PhyRdy Change from Serror too */
+ ahci_scr_write(ap, SCR_ERROR, (1 << 16));
+
+ /*
+ * Clear flag to indicate that we should ignore all PhyRdy
+ * state changes
+ */
+ ap->flags &= ~AHCI_FLAG_NO_HOTPLUG;
+
+ /*
+ * Enable interrupts on Phy Ready.
+ */
+ pp->intr_mask |= PORT_IRQ_PHYRDY;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+ /*
+ * don't change the link pm policy - we can be called
+ * just to turn of link pm temporarily
+ */
+ return 0;
+}
+
+static int ahci_enable_alpm(struct ata_port *ap,
+ enum scsi_host_link_pm policy)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd, scontrol, sstatus;
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 asp;
+
+ /* Make sure the host is capable of link power management */
+ if (!(hpriv->cap & HOST_CAP_ALPM)) {
+ ap->pm_policy = SHOST_NOT_AVAILABLE;
+ return -EINVAL;
+ }
+
+ /* make sure we have a device attached */
+ sstatus = readl(port_mmio + PORT_SCR_STAT);
+ if (!(sstatus & 0xf00)) {
+ ap->pm_policy = SHOST_NOT_AVAILABLE;
+ return -EINVAL;
+ }
+
+ switch(policy) {
+ case SHOST_MAX_PERFORMANCE:
+ ahci_disable_alpm(ap);
+ ap->pm_policy = policy;
+ return 0;
+ case SHOST_NOT_AVAILABLE:
+ case SHOST_MIN_POWER:
+ /*
+ * if we came here with SHOST_NOT_AVAILABLE,
+ * it just means this is the first time we
+ * have tried to enable - so try to do
+ * min_power
+ */
+ ap->pm_policy = SHOST_MIN_POWER;
+
+ /* configure HBA to enter SLUMBER */
+ asp = PORT_CMD_ASP;
+ break;
+ case SHOST_MEDIUM_POWER:
+ /* configure HBA to enter PARTIAL */
+ ap->pm_policy = policy;
+ asp = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Disable interrupts on Phy Ready. This keeps us from
+ * getting woken up due to spurious phy ready interrupts
+ * TBD - Hot plug should be done via polling now, is
+ * that even supported?
+ */
+ pp->intr_mask &= ~PORT_IRQ_PHYRDY;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+ /*
+ * Set a flag to indicate that we should ignore all PhyRdy
+ * state changes since these can happen now whenever we
+ * change link state
+ */
+ ap->flags |= AHCI_FLAG_NO_HOTPLUG;
+
+ /* get the existing command bits */
+ cmd = readl(port_mmio + PORT_CMD);
+
+ /*
+ * enable Interface Power Management State Transitions
+ * This is accomplished by clearing bits 8:11 of the
+ * SATA Control register
+ */
+ scontrol = readl(port_mmio + PORT_SCR_CTL);
+ scontrol &= ~(0x3 << 8);
+ writel(scontrol, port_mmio + PORT_SCR_CTL);
+
+ /*
+ * Set ASP based on Policy
+ */
+ cmd |= asp;
+
+ /*
+ * Setting this bit will instruct the HBA to aggressively
+ * enter a lower power link state when it's appropriate and
+ * based on the value set above for ASP
+ */
+ cmd |= PORT_CMD_ALPE;
+
+ /* write out new cmd value */
+ writel(cmd, port_mmio + PORT_CMD);
+ cmd = readl(port_mmio + PORT_CMD);
+ return 0;
+}
+
#ifdef CONFIG_PM
static void ahci_power_down(struct ata_port *ap)
{
@@ -1244,6 +1406,10 @@ static void ahci_host_intr(struct ata_po
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
+ if ((ap->flags & AHCI_FLAG_NO_HOTPLUG) &&
+ (status & PORT_IRQ_PHYRDY))
+ status &= ~PORT_IRQ_PHYRDY;
+
if (unlikely(status & PORT_IRQ_ERROR)) {
ahci_error_intr(ap, status);
return;
@@ -1759,6 +1925,7 @@ static int ahci_init_one(struct pci_dev
ap->ioaddr.cmd_addr = port_mmio;
ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
+ ap->pm_policy = SHOST_NOT_AVAILABLE;
} else
host->ports[i]->ops = &ata_dummy_port_ops;
}
next prev parent reply other threads:[~2007-06-20 21:27 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20070611184146.448266229@intel.com>
2007-06-11 18:48 ` [patch 1/3] Store interrupt value Kristen Carlson Accardi
2007-06-11 19:59 ` Jeff Garzik
2007-06-11 18:48 ` [patch 2/3] Expose Power Management Policy option to users Kristen Carlson Accardi
2007-06-11 20:00 ` Jeff Garzik
2007-06-12 17:46 ` [patch 2a/3] " Kristen Carlson Accardi
2007-06-13 15:26 ` James Bottomley
2007-06-13 20:48 ` Jeff Garzik
2007-06-14 16:39 ` Kristen Carlson Accardi
2007-06-14 17:44 ` Jeff Garzik
2007-06-12 17:47 ` [patch 2b/3] " Kristen Carlson Accardi
2007-06-20 21:22 ` Kristen Carlson Accardi
2007-06-11 18:48 ` [patch 3/3] Enable Aggressive Link Power management for AHCI controllers Kristen Carlson Accardi
2007-06-11 20:01 ` Jeff Garzik
2007-06-12 1:11 ` Henrique de Moraes Holschuh
2007-06-12 1:16 ` Arjan van de Ven
2007-06-12 1:54 ` Dagfinn Ilmari Mannsåker
2007-06-12 1:59 ` Jeff Garzik
2007-06-12 3:59 ` Henrique de Moraes Holschuh
2007-06-12 3:59 ` Arjan van de Ven
2007-06-12 9:09 ` Matthew Garrett
2007-06-12 12:18 ` Henrique de Moraes Holschuh
2007-06-12 13:50 ` Matthew Garrett
2007-06-12 14:17 ` Henrique de Moraes Holschuh
2007-06-12 15:38 ` Matthew Garrett
2007-06-12 15:45 ` Tejun Heo
2007-06-12 15:56 ` Matthew Garrett
2007-06-12 15:46 ` Jeff Garzik
2007-06-12 15:58 ` Matthew Garrett
2007-06-12 16:18 ` Jeff Garzik
2007-06-12 16:27 ` Kristen Carlson Accardi
2007-06-20 21:23 ` Kristen Carlson Accardi [this message]
2007-06-21 13:08 ` Jens Axboe
2007-06-22 17:15 ` Kristen Carlson Accardi
2007-06-22 19:00 ` Jens Axboe
2007-06-26 15:24 ` Kristen Carlson Accardi
[not found] <20070801210713.809095009@intel.com>
2007-08-01 21:29 ` Kristen Carlson Accardi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070620142342.404856fe.kristen.c.accardi@intel.com \
--to=kristen.c.accardi@intel.com \
--cc=arjan@linux.intel.com \
--cc=htejun@gmail.com \
--cc=jeff@garzik.org \
--cc=linux-ide@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®