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