summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'sys-kernel/thinkpad-sources/files/2.6.23/combined-2.6.23-cph.patch')
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.23/combined-2.6.23-cph.patch620
1 files changed, 620 insertions, 0 deletions
diff --git a/sys-kernel/thinkpad-sources/files/2.6.23/combined-2.6.23-cph.patch b/sys-kernel/thinkpad-sources/files/2.6.23/combined-2.6.23-cph.patch
new file mode 100644
index 000000000..28af1a623
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.23/combined-2.6.23-cph.patch
@@ -0,0 +1,620 @@
+diff -ruNp linux-2.6.23.orig/Documentation/scsi/link_power_management_policy.txt linux-2.6.23/Documentation/scsi/link_power_management_policy.txt
+--- linux-2.6.23.orig/Documentation/scsi/link_power_management_policy.txt 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.23/Documentation/scsi/link_power_management_policy.txt 2007-10-15 21:34:38.000000000 -0400
+@@ -0,0 +1,19 @@
++This parameter allows the user to set the link (interface) power management.
++There are 3 possible options:
++
++Value Effect
++----------------------------------------------------------------------------
++min_power Tell the controller to try to make the link use the
++ least possible power when possible. This may
++ sacrifice some performance due to increased latency
++ when coming out of lower power states.
++
++max_performance Generally, this means no power management. Tell
++ the controller to have performance be a priority
++ over power management.
++
++medium_power Tell the controller to enter a lower power state
++ when possible, but do not enter the lowest power
++ state, thus improving latency over min_power setting.
++
++
+diff -ruNp linux-2.6.23.orig/drivers/ata/ahci.c linux-2.6.23/drivers/ata/ahci.c
+--- linux-2.6.23.orig/drivers/ata/ahci.c 2007-10-09 16:31:38.000000000 -0400
++++ linux-2.6.23/drivers/ata/ahci.c 2007-10-15 21:35:48.000000000 -0400
+@@ -48,6 +48,9 @@
+ #define DRV_NAME "ahci"
+ #define DRV_VERSION "2.3"
+
++static int ahci_enable_alpm(struct ata_port *ap,
++ enum link_pm policy);
++static int ahci_disable_alpm(struct ata_port *ap);
+
+ enum {
+ AHCI_PCI_BAR = 5,
+@@ -98,6 +101,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_SNTF = (1 << 29), /* SNotification register */
+ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
+@@ -153,6 +157,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 */
+@@ -175,6 +181,7 @@ enum {
+ AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */
+ AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */
+ AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */
++ AHCI_FLAG_NO_HOTPLUG = (1 << 31), /* ignore PxSERR.DIAG.N */
+
+ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+@@ -215,6 +222,7 @@ struct ahci_port_priv {
+ unsigned int ncq_saw_d2h:1;
+ unsigned int ncq_saw_dmas:1;
+ unsigned int ncq_saw_sdb:1;
++ u32 intr_mask; /* interrupts to enable */
+ };
+
+ static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+@@ -242,6 +250,11 @@ static int ahci_pci_device_suspend(struc
+ static int ahci_pci_device_resume(struct pci_dev *pdev);
+ #endif
+
++static struct class_device_attribute *ahci_shost_attrs[] = {
++ &class_device_attr_link_power_management_policy,
++ NULL
++};
++
+ static struct scsi_host_template ahci_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+@@ -259,6 +272,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,
++ .shost_attrs = ahci_shost_attrs,
+ };
+
+ static const struct ata_port_operations ahci_ops = {
+@@ -290,6 +304,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,
+@@ -778,6 +794,156 @@ 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) | (1 << 18)));
++
++ /*
++ * 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 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 = NOT_AVAILABLE;
++ return -EINVAL;
++ }
++
++ /* make sure we have a device attached */
++ sstatus = readl(port_mmio + PORT_SCR_STAT);
++ if (!(sstatus & 0xf00)) {
++ ap->pm_policy = NOT_AVAILABLE;
++ return -EINVAL;
++ }
++
++ switch (policy) {
++ case MAX_PERFORMANCE:
++ case NOT_AVAILABLE:
++ /*
++ * if we came here with NOT_AVAILABLE,
++ * it just means this is the first time we
++ * have tried to enable - default to max performance,
++ * and let the user go to lower power modes on request.
++ */
++ ahci_disable_alpm(ap);
++ ap->pm_policy = MAX_PERFORMANCE;
++ return 0;
++ case MIN_POWER:
++ /* configure HBA to enter SLUMBER */
++ asp = PORT_CMD_ASP;
++ break;
++ case MEDIUM_POWER:
++ /* configure HBA to enter PARTIAL */
++ asp = 0;
++ break;
++ default:
++ return -EINVAL;
++ }
++ ap->pm_policy = policy;
++
++ /*
++ * 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)
+ {
+@@ -1355,6 +1521,17 @@ static void ahci_port_intr(struct ata_po
+ status = readl(port_mmio + PORT_IRQ_STAT);
+ writel(status, port_mmio + PORT_IRQ_STAT);
+
++ /* If we are getting PhyRdy, this is
++ * just a power state change, we should
++ * clear out this, plus the PhyRdy/Comm
++ * Wake bits from Serror
++ */
++ if ((ap->flags & AHCI_FLAG_NO_HOTPLUG) &&
++ (status & PORT_IRQ_PHYRDY)) {
++ status &= ~PORT_IRQ_PHYRDY;
++ ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
++ }
++
+ if (unlikely(status & PORT_IRQ_ERROR)) {
+ ahci_error_intr(ap, status);
+ return;
+@@ -1520,6 +1697,7 @@ static void ahci_thaw(struct ata_port *a
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 tmp;
++ struct ahci_port_priv *pp = ap->private_data;
+
+ /* clear IRQ */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+@@ -1527,7 +1705,7 @@ static void ahci_thaw(struct ata_port *a
+ writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
+
+ /* turn IRQ back on */
+- writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
++ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+ }
+
+ static void ahci_error_handler(struct ata_port *ap)
+@@ -1681,6 +1859,12 @@ static int ahci_port_start(struct ata_po
+ pp->cmd_tbl = mem;
+ pp->cmd_tbl_dma = mem_dma;
+
++ /*
++ * Save off initial list of interrupts to be enabled.
++ * This could be changed later
++ */
++ pp->intr_mask = DEF_PORT_IRQ;
++
+ ap->private_data = pp;
+
+ /* engage engines, captain */
+@@ -1854,6 +2038,9 @@ static int ahci_init_one(struct pci_dev
+ struct ata_port *ap = host->ports[i];
+ void __iomem *port_mmio = ahci_port_base(ap);
+
++ /* set initial link pm policy */
++ ap->pm_policy = NOT_AVAILABLE;
++
+ /* standard SATA port setup */
+ if (hpriv->port_map & (1 << i))
+ ap->ioaddr.cmd_addr = port_mmio;
+diff -ruNp linux-2.6.23.orig/drivers/ata/libata-core.c linux-2.6.23/drivers/ata/libata-core.c
+--- linux-2.6.23.orig/drivers/ata/libata-core.c 2007-10-09 16:31:38.000000000 -0400
++++ linux-2.6.23/drivers/ata/libata-core.c 2007-10-15 21:34:39.000000000 -0400
+@@ -1994,6 +1994,9 @@ int ata_dev_configure(struct ata_device
+ if (dev->flags & ATA_DFLAG_LBA48)
+ dev->max_sectors = ATA_MAX_SECTORS_LBA48;
+
++ if (ata_id_has_hipm(dev->id) || ata_id_has_dipm(dev->id))
++ dev->flags |= ATA_DFLAG_IPM;
++
+ if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
+ /* Let the user know. We don't want to disallow opens for
+ rescue purposes, or in case the vendor is just a blithering
+@@ -2019,6 +2022,13 @@ int ata_dev_configure(struct ata_device
+ dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
+ dev->max_sectors);
+
++ if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) {
++ dev->horkage |= ATA_HORKAGE_IPM;
++
++ /* reset link pm_policy for this port to no pm */
++ ap->pm_policy = MAX_PERFORMANCE;
++ }
++
+ if (ap->ops->dev_config)
+ ap->ops->dev_config(dev);
+
+@@ -5892,6 +5902,27 @@ int ata_flush_cache(struct ata_device *d
+ return 0;
+ }
+
++static void ata_host_disable_link_pm(struct ata_host *host)
++{
++ int i;
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++ if (ap->ops->disable_pm)
++ ap->ops->disable_pm(ap);
++ }
++}
++
++static void ata_host_enable_link_pm(struct ata_host *host)
++{
++ int i;
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap = host->ports[i];
++ ata_scsi_set_link_pm_policy(ap, ap->pm_policy);
++ }
++}
++
+ #ifdef CONFIG_PM
+ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
+ unsigned int action, unsigned int ehi_flags,
+@@ -5959,6 +5990,12 @@ int ata_host_suspend(struct ata_host *ho
+ {
+ int rc;
+
++ /*
++ * disable link pm on all ports before requesting
++ * any pm activity
++ */
++ ata_host_disable_link_pm(host);
++
+ rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
+ if (rc == 0)
+ host->dev->power.power_state = mesg;
+@@ -5981,6 +6018,9 @@ void ata_host_resume(struct ata_host *ho
+ ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET,
+ ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+ host->dev->power.power_state = PMSG_ON;
++
++ /* reenable link pm */
++ ata_host_enable_link_pm(host);
+ }
+ #endif
+
+@@ -6478,6 +6518,7 @@ int ata_host_register(struct ata_host *h
+ struct ata_port *ap = host->ports[i];
+
+ ata_scsi_scan_host(ap, 1);
++ ata_scsi_set_link_pm_policy(ap, ap->pm_policy);
+ }
+
+ return 0;
+diff -ruNp linux-2.6.23.orig/drivers/ata/libata-scsi.c linux-2.6.23/drivers/ata/libata-scsi.c
+--- linux-2.6.23.orig/drivers/ata/libata-scsi.c 2007-10-09 16:31:38.000000000 -0400
++++ linux-2.6.23/drivers/ata/libata-scsi.c 2007-10-15 21:34:39.000000000 -0400
+@@ -111,6 +111,78 @@ static struct scsi_transport_template at
+ };
+
+
++static const struct {
++ enum link_pm value;
++ char *name;
++} link_pm_policy[] = {
++ { NOT_AVAILABLE, "max_performance" },
++ { MIN_POWER, "min_power" },
++ { MAX_PERFORMANCE, "max_performance" },
++ { MEDIUM_POWER, "medium_power" },
++};
++
++const char *ata_scsi_link_pm_policy(enum link_pm policy)
++{
++ int i;
++ char *name = NULL;
++
++ for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++) {
++ if (link_pm_policy[i].value == policy) {
++ name = link_pm_policy[i].name;
++ break;
++ }
++ }
++ return name;
++}
++
++static ssize_t store_link_pm_policy(struct class_device *class_dev,
++ const char *buf, size_t count)
++{
++ struct Scsi_Host *shost = class_to_shost(class_dev);
++ struct ata_port *ap = ata_shost_to_port(shost);
++ enum link_pm policy = 0;
++ int i;
++
++ /*
++ * we are skipping array location 0 on purpose - this
++ * is because a value of NOT_AVAILABLE is displayed
++ * to the user as max_performance, but when the user
++ * writes "max_performance", they actually want the
++ * value to match MAX_PERFORMANCE.
++ */
++ for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {
++ const int len = strlen(link_pm_policy[i].name);
++ if (strncmp(link_pm_policy[i].name, buf, len) == 0 &&
++ buf[len] == '\n') {
++ policy = link_pm_policy[i].value;
++ break;
++ }
++ }
++ if (!policy)
++ return -EINVAL;
++
++ if (ata_scsi_set_link_pm_policy(ap, policy))
++ return -EINVAL;
++ return count;
++}
++
++static ssize_t
++show_link_pm_policy(struct class_device *class_dev, char *buf)
++{
++ struct Scsi_Host *shost = class_to_shost(class_dev);
++ struct ata_port *ap = ata_shost_to_port(shost);
++ const char *policy =
++ ata_scsi_link_pm_policy(ap->pm_policy);
++
++ if (!policy)
++ return -EINVAL;
++
++ return snprintf(buf, 23, "%s\n", policy);
++}
++CLASS_DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
++ show_link_pm_policy, store_link_pm_policy);
++EXPORT_SYMBOL_GPL(class_device_attr_link_power_management_policy);
++
+ static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+ {
+@@ -2905,6 +2977,47 @@ void ata_scsi_simulate(struct ata_device
+ }
+ }
+
++int ata_scsi_set_link_pm_policy(struct ata_port *ap,
++ enum link_pm policy)
++{
++ int rc = -EINVAL;
++ int i;
++
++ /*
++ * make sure no broken devices are on this port,
++ * and that all devices support interface power
++ * management
++ */
++ for (i = 0; i < ATA_MAX_DEVICES; i++) {
++ struct ata_device *dev = &ap->device[i];
++
++ /* only check drives which exist */
++ if (!ata_dev_enabled(dev))
++ continue;
++
++ /*
++ * do we need to handle the case where we've hotplugged
++ * a broken drive (since hotplug and ALPM are mutually
++ * exclusive) ?
++ *
++ * If so, if we detect a broken drive on a port with
++ * alpm already enabled, then we should reset the policy
++ * to off for the entire port.
++ */
++ if ((dev->horkage & ATA_HORKAGE_IPM) ||
++ !(dev->flags & ATA_DFLAG_IPM)) {
++ ata_dev_printk(dev, KERN_ERR,
++ "Unable to set Link PM policy\n");
++ ap->pm_policy = MAX_PERFORMANCE;
++ }
++ }
++
++ if (ap->ops->enable_pm)
++ rc = ap->ops->enable_pm(ap, policy);
++ return rc;
++}
++EXPORT_SYMBOL_GPL(ata_scsi_set_link_pm_policy);
++
+ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
+ {
+ int i, rc;
+diff -ruNp linux-2.6.23.orig/include/linux/ata.h linux-2.6.23/include/linux/ata.h
+--- linux-2.6.23.orig/include/linux/ata.h 2007-10-09 16:31:38.000000000 -0400
++++ linux-2.6.23/include/linux/ata.h 2007-10-15 21:34:39.000000000 -0400
+@@ -368,6 +368,12 @@ struct ata_taskfile {
+ ((u64) (id)[(n) + 0]) )
+
+ #define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
++#define ata_id_has_hipm(id) \
++ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
++ ((id)[76] & (1 << 9)) )
++#define ata_id_has_dipm(id) \
++ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
++ ((id)[78] & (1 << 3)) )
+
+ static inline unsigned int ata_id_major_version(const u16 *id)
+ {
+diff -ruNp linux-2.6.23.orig/include/linux/libata.h linux-2.6.23/include/linux/libata.h
+--- linux-2.6.23.orig/include/linux/libata.h 2007-10-09 16:31:38.000000000 -0400
++++ linux-2.6.23/include/linux/libata.h 2007-10-15 21:35:14.000000000 -0400
+@@ -139,7 +139,8 @@ enum {
+ ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */
+ ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
+ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
+- ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
++ ATA_DFLAG_IPM = (1 << 7), /* device supports IPM */
++ ATA_DFLAG_CFG_MASK = (1 << 12) - 1,
+
+ ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */
+ ATA_DFLAG_NCQ_OFF = (1 << 9), /* device limited to non-NCQ mode */
+@@ -304,6 +305,7 @@ enum {
+ ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */
+ ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */
+ ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */
++ ATA_HORKAGE_IPM = (1 << 5), /* LPM problems */
+ };
+
+ enum hsm_task_states {
+@@ -342,6 +344,18 @@ typedef int (*ata_reset_fn_t)(struct ata
+ unsigned long deadline);
+ typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
+
++/*
++ * host pm policy: If you alter this, you also need to alter scsi_sysfs.c
++ * (for the ascii descriptions)
++ */
++enum link_pm {
++ NOT_AVAILABLE,
++ MIN_POWER,
++ MAX_PERFORMANCE,
++ MEDIUM_POWER,
++};
++extern struct class_device_attribute class_device_attr_link_power_management_policy;
++
+ struct ata_ioports {
+ void __iomem *cmd_addr;
+ void __iomem *data_addr;
+@@ -568,6 +582,7 @@ struct ata_port {
+
+ pm_message_t pm_mesg;
+ int *pm_result;
++ enum link_pm pm_policy;
+
+ struct timer_list fastdrain_timer;
+ unsigned long fastdrain_cnt;
+@@ -633,7 +648,8 @@ struct ata_port_operations {
+
+ int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
+ int (*port_resume) (struct ata_port *ap);
+-
++ int (*enable_pm) (struct ata_port *ap, enum link_pm policy);
++ int (*disable_pm) (struct ata_port *ap);
+ int (*port_start) (struct ata_port *ap);
+ void (*port_stop) (struct ata_port *ap);
+
+@@ -840,7 +856,7 @@ extern int ata_cable_40wire(struct ata_p
+ extern int ata_cable_80wire(struct ata_port *ap);
+ extern int ata_cable_sata(struct ata_port *ap);
+ extern int ata_cable_unknown(struct ata_port *ap);
+-
++extern int ata_scsi_set_link_pm_policy(struct ata_port *ap, enum link_pm);
+ /*
+ * Timing helpers
+ */
+@@ -869,7 +885,6 @@ enum {
+ ATA_TIMING_CYCLE | ATA_TIMING_UDMA,
+ };
+
+-
+ #ifdef CONFIG_PCI
+ struct pci_bits {
+ unsigned int reg; /* PCI config register to read */