summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'sys-kernel/thinkpad-sources/files/2.6.27/power-off-unused-ports.patch')
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.27/power-off-unused-ports.patch133
1 files changed, 133 insertions, 0 deletions
diff --git a/sys-kernel/thinkpad-sources/files/2.6.27/power-off-unused-ports.patch b/sys-kernel/thinkpad-sources/files/2.6.27/power-off-unused-ports.patch
new file mode 100644
index 0000000..d7225a2
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.27/power-off-unused-ports.patch
@@ -0,0 +1,133 @@
+ drivers/ata/ahci.c | 21 +++++++++++++++++++++
+ drivers/ata/libata-core.c | 24 ++++++++++++++++++++++++
+ include/linux/libata.h | 1 +
+ 3 files changed, 46 insertions(+)
+
+Index: linux-ahci-phy/drivers/ata/ahci.c
+===================================================================
+--- linux-ahci-phy.orig/drivers/ata/ahci.c 2008-05-08 14:29:02.000000000 -0700
++++ linux-ahci-phy/drivers/ata/ahci.c 2008-05-08 14:31:05.000000000 -0700
+@@ -53,14 +53,18 @@ static int ahci_skip_host_reset;
+ module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
+ MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
+
++static int ahci_power_save = 1;
++module_param_named(power_save, ahci_power_save, int, 0444);
++MODULE_PARM_DESC(power_save, "Power off unused ports (0=don't power off, 1=power off)");
+ static int ahci_enable_alpm(struct ata_port *ap,
+ enum link_pm policy);
+ static void ahci_disable_alpm(struct ata_port *ap);
+ static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
+ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
+ size_t size);
+ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
+ ssize_t size);
++static int ahci_is_hotplug_capable(struct ata_port *ap);
+ #define MAX_SLOTS 8
+
+ enum {
+@@ -166,6 +170,8 @@ enum {
+ 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_ESP = (1 << 21), /* External SATA Port */
++ PORT_CMD_HPCP = (1 << 18), /* port is hot plug capable */
+ PORT_CMD_PMP = (1 << 17), /* PMP attached */
+ PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
+ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
+@@ -1900,6 +1906,18 @@ static int ahci_pci_device_resume(struct
+ }
+ #endif
+
++static int ahci_is_hotplug_capable(struct ata_port *ap)
++{
++ void __iomem *port_mmio = ahci_port_base(ap);
++ u8 cmd;
++
++ if (!ahci_power_save)
++ return 1;
++
++ cmd = readl(port_mmio + PORT_CMD);
++ return ((cmd & PORT_CMD_HPCP) || (cmd & PORT_CMD_ESP));
++}
++
+ static int ahci_port_start(struct ata_port *ap)
+ {
+ struct device *dev = ap->host->dev;
+@@ -1951,6 +1969,9 @@ static int ahci_port_start(struct ata_po
+
+ ap->private_data = pp;
+
++ /* set some flags based on port capabilities */
++ if (!ahci_is_hotplug_capable(ap))
++ ap->flags |= ATA_FLAG_NO_HOTPLUG;
+ /* engage engines, captain */
+ return ahci_port_resume(ap);
+ }
+Index: linux-ahci-phy/drivers/ata/libata-core.c
+===================================================================
+--- linux-ahci-phy.orig/drivers/ata/libata-core.c 2008-05-08 14:28:57.000000000 -0700
++++ linux-ahci-phy/drivers/ata/libata-core.c 2008-05-08 14:29:50.000000000 -0700
+@@ -162,6 +162,19 @@ MODULE_DESCRIPTION("Library module for A
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION(DRV_VERSION);
+
++static void ata_phy_offline(struct ata_link *link)
++{
++ u32 scontrol;
++ int rc;
++
++ /* set DET to 4 */
++ rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
++ if (rc)
++ return;
++ scontrol &= ~0xf;
++ scontrol |= (1 << 2);
++ sata_scr_write(link, SCR_CONTROL, scontrol);
++}
+
+ /**
+ * ata_force_cbl - force cable type according to libata.force
+@@ -2671,6 +2684,7 @@ void ata_port_disable(struct ata_port *a
+ ap->link.device[0].class = ATA_DEV_NONE;
+ ap->link.device[1].class = ATA_DEV_NONE;
+ ap->flags |= ATA_FLAG_DISABLED;
++ ata_phy_offline(&ap->link);
+ }
+
+ /**
+@@ -5609,6 +5623,8 @@ int ata_host_register(struct ata_host *h
+ if (ap->ops->error_handler) {
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ unsigned long flags;
++ int device_attached = 0;
++ struct ata_device *dev;
+
+ ata_port_probe(ap);
+
+@@ -5627,6 +5643,14 @@ int ata_host_register(struct ata_host *h
+
+ /* wait for EH to finish */
+ ata_port_wait_eh(ap);
++ ata_link_for_each_dev(dev, &ap->link)
++ if (ata_dev_enabled(dev))
++ device_attached++;
++ if (!device_attached &&
++ (ap->flags & ATA_FLAG_NO_HOTPLUG)) {
++ /* no device present, disable port */
++ ata_port_disable(ap);
++ }
+ } else {
+ DPRINTK("ata%u: bus probe begin\n", ap->print_id);
+ rc = ata_bus_probe(ap);
+Index: linux-ahci-phy/include/linux/libata.h
+===================================================================
+--- linux-ahci-phy.orig/include/linux/libata.h 2008-05-08 14:28:57.000000000 -0700
++++ linux-ahci-phy/include/linux/libata.h 2008-05-08 14:29:50.000000000 -0700
+@@ -207,4 +207,6 @@ ATA_FLAG_DISABLED = (1 << 23), /* port is disabled, ignore it */
+
+ /* bits 24:31 of ap->flags are reserved for LLD specific flags */
++
++ ATA_FLAG_NO_HOTPLUG = (1 << 32), /* port doesn't support HP */
+
+ /* struct ata_port pflags */