diff options
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.patch | 620 |
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 */ |