* [patch 1/2] allow user to power off unused ports via sysfs
[not found] <20080702225743.518230210@intel.com>
@ 2008-07-02 23:14 ` kristen.c.accardi
2008-07-04 12:58 ` Jeff Garzik
2008-07-11 13:50 ` Jeff Garzik
2008-07-02 23:14 ` [patch 2/2] set default of ahci driver to power off unused ports kristen.c.accardi
1 sibling, 2 replies; 5+ messages in thread
From: kristen.c.accardi @ 2008-07-02 23:14 UTC (permalink / raw)
To: jeff; +Cc: linux-ide, Kristen Carlson Accardi
This patch expands the definition of link power management to
include the notion of simply powering the entire port off.
We add a new valid value for link_power_management_policy:
power_off: phy is not on at all.
min_power: driver uses minimum possible power. hotplug
may or may not be available.
medium_power: best power/performance tradeoff. hotplug
may or may not be available
max_performance: max performance without regard to power
hot plug is available.
Additionally - this patch modifies the libata-core to
power off the port automatically at init time if the
driver marks the port as not hotpluggable.
The user may not power off a port if it is occupied.
If the port is powered off, and a new drive is plugged
in, the drive will not be detected until the port is
powered back up by setting the link_power_management_policy
to "max_performance".
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
---
drivers/ata/libata-core.c | 58 +++++++++++++++++++++++++++++++++++++++++++++-
drivers/ata/libata-scsi.c | 1
include/linux/libata.h | 2 +
3 files changed, 60 insertions(+), 1 deletion(-)
Index: linux-ahci-phy/drivers/ata/libata-core.c
===================================================================
--- linux-ahci-phy.orig/drivers/ata/libata-core.c 2008-06-27 13:32:51.000000000 -0700
+++ linux-ahci-phy/drivers/ata/libata-core.c 2008-07-01 16:33:00.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
@@ -953,6 +966,7 @@ static int ata_dev_set_dipm(struct ata_d
* disallow all transitions which effectively
* disable DIPM anyway.
*/
+ default:
break;
}
@@ -980,6 +994,22 @@ void ata_dev_enable_pm(struct ata_device
int rc = 0;
struct ata_port *ap = dev->link->ap;
+ /*
+ * if we don't have a device attached, all we can
+ * do is power off
+ */
+ if (!ata_dev_enabled(dev) && policy == POWER_OFF) {
+ ap->flags |= ATA_FLAG_NO_HOTPLUG;
+ ata_phy_offline(&ap->link);
+ goto enable_pm_out;
+ }
+
+ /*
+ * if there's no device attached, we are done
+ */
+ if (!ata_dev_enabled(dev))
+ return;
+
/* set HIPM first, then DIPM */
if (ap->ops->enable_pm)
rc = ap->ops->enable_pm(ap, policy);
@@ -1020,10 +1050,24 @@ static void ata_dev_disable_pm(struct at
void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy)
{
- ap->pm_policy = policy;
ap->link.eh_info.action |= ATA_EH_LPM;
+
+ /*
+ * if we are coming from a state of OFF to ON, we need
+ * to reset the link and scan for devices in case someone
+ * plugged something in while we were off.
+ * Clear the NO_HOTPLUG flag because we are leaving the
+ * phy on now.
+ */
+ if (ap->pm_policy == POWER_OFF && policy != POWER_OFF) {
+ ap->flags &= ~ATA_FLAG_NO_HOTPLUG;
+ ap->link.eh_info.probe_mask |= ATA_ALL_DEVICES;
+ ap->link.eh_info.flags |= ATA_EH_RESET;
+ }
ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY;
+ ap->pm_policy = policy;
ata_port_schedule_eh(ap);
+ ata_port_wait_eh(ap);
}
#ifdef CONFIG_PM
@@ -2678,6 +2722,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);
}
/**
@@ -5614,6 +5659,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);
@@ -5632,6 +5679,15 @@ 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 */
+ ap->pm_policy = POWER_OFF;
+ 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-06-27 13:32:57.000000000 -0700
+++ linux-ahci-phy/include/linux/libata.h 2008-06-27 13:38:11.000000000 -0700
@@ -190,6 +190,7 @@ enum {
ATA_FLAG_AN = (1 << 18), /* controller supports AN */
ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */
ATA_FLAG_IPM = (1 << 20), /* driver can handle IPM */
+ ATA_FLAG_NO_HOTPLUG = (1 << 21), /* port doesn't support HP */
/* The following flag belongs to ap->pflags but is kept in
* ap->flags because it's referenced in many LLDs and will be
@@ -439,6 +440,7 @@ enum link_pm {
MIN_POWER,
MAX_PERFORMANCE,
MEDIUM_POWER,
+ POWER_OFF,
};
extern struct device_attribute dev_attr_link_power_management_policy;
Index: linux-ahci-phy/drivers/ata/libata-scsi.c
===================================================================
--- linux-ahci-phy.orig/drivers/ata/libata-scsi.c 2008-06-27 13:32:51.000000000 -0700
+++ linux-ahci-phy/drivers/ata/libata-scsi.c 2008-06-27 13:38:11.000000000 -0700
@@ -122,6 +122,7 @@ static const struct {
{ MIN_POWER, "min_power" },
{ MAX_PERFORMANCE, "max_performance" },
{ MEDIUM_POWER, "medium_power" },
+ { POWER_OFF, "power_off" },
};
static const char *ata_scsi_lpm_get(enum link_pm policy)
--
^ permalink raw reply [flat|nested] 5+ messages in thread
* [patch 2/2] set default of ahci driver to power off unused ports
[not found] <20080702225743.518230210@intel.com>
2008-07-02 23:14 ` [patch 1/2] allow user to power off unused ports via sysfs kristen.c.accardi
@ 2008-07-02 23:14 ` kristen.c.accardi
2008-07-04 13:02 ` Jeff Garzik
1 sibling, 1 reply; 5+ messages in thread
From: kristen.c.accardi @ 2008-07-02 23:14 UTC (permalink / raw)
To: jeff; +Cc: linux-ide, Kristen Carlson Accardi
If the port isn't either a drive bay or an external SATA port,
mark the port not-hotpluggable. This will cause libata to
power off the phy if it is unoccupied. This saves .75 watts
on most laptops. A module parameter can be used to override this
behavior and allow the phy's to be powered up regardless of whether it
has externally accessible SATA ports.
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
---
drivers/ata/ahci.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
Index: linux-ahci-phy/drivers/ata/ahci.c
===================================================================
--- linux-ahci-phy.orig/drivers/ata/ahci.c 2008-07-01 16:27:56.000000000 -0700
+++ linux-ahci-phy/drivers/ata/ahci.c 2008-07-01 16:35:03.000000000 -0700
@@ -53,9 +53,13 @@ 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 int ahci_is_hotplug_capable(struct ata_port *ap);
enum {
AHCI_PCI_BAR = 5,
@@ -168,6 +172,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 */
@@ -1998,6 +2004,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;
@@ -2049,6 +2067,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);
}
--
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [patch 1/2] allow user to power off unused ports via sysfs
2008-07-02 23:14 ` [patch 1/2] allow user to power off unused ports via sysfs kristen.c.accardi
@ 2008-07-04 12:58 ` Jeff Garzik
2008-07-11 13:50 ` Jeff Garzik
1 sibling, 0 replies; 5+ messages in thread
From: Jeff Garzik @ 2008-07-04 12:58 UTC (permalink / raw)
To: kristen.c.accardi; +Cc: linux-ide, linux-scsi
kristen.c.accardi@intel.com wrote:
> This patch expands the definition of link power management to
> include the notion of simply powering the entire port off.
> We add a new valid value for link_power_management_policy:
>
> power_off: phy is not on at all.
> min_power: driver uses minimum possible power. hotplug
> may or may not be available.
> medium_power: best power/performance tradeoff. hotplug
> may or may not be available
> max_performance: max performance without regard to power
> hot plug is available.
>
> Additionally - this patch modifies the libata-core to
> power off the port automatically at init time if the
> driver marks the port as not hotpluggable.
>
> The user may not power off a port if it is occupied.
> If the port is powered off, and a new drive is plugged
> in, the drive will not be detected until the port is
> powered back up by setting the link_power_management_policy
> to "max_performance".
>
> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
> ---
> drivers/ata/libata-core.c | 58 +++++++++++++++++++++++++++++++++++++++++++++-
> drivers/ata/libata-scsi.c | 1
> include/linux/libata.h | 2 +
> 3 files changed, 60 insertions(+), 1 deletion(-)
Looks good to me, ACK.
I'm apply soonish, unless there are other complaints.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [patch 2/2] set default of ahci driver to power off unused ports
2008-07-02 23:14 ` [patch 2/2] set default of ahci driver to power off unused ports kristen.c.accardi
@ 2008-07-04 13:02 ` Jeff Garzik
0 siblings, 0 replies; 5+ messages in thread
From: Jeff Garzik @ 2008-07-04 13:02 UTC (permalink / raw)
To: kristen.c.accardi; +Cc: linux-ide
kristen.c.accardi@intel.com wrote:
> If the port isn't either a drive bay or an external SATA port,
> mark the port not-hotpluggable.
That's just flat out incorrect, though.
We've been hotplugging SATA cables since SATA began, when the _most
common_ hotplug case was where a port was neither a drive bay nor eSATA.
Part of the beauty of SATA is being able to just 'yank the cable'.
PORT_CMD_ESP and PORT_CMD_HPCP are positive indicators of hotplug
capability, but are not exclusively such.
So, this patch would create regressions for people in servers or
desktops or development systems that wish to retain their _existing_
ability to hotplug.
One guaranteed way to avoid regressions is to default ahci_power_save to
zero, but that's then not helpful to Linux users in general, few of
which will know of this module option and turn it on.
This is actually wandering into system-wide power policy :/
Jeff
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [patch 1/2] allow user to power off unused ports via sysfs
2008-07-02 23:14 ` [patch 1/2] allow user to power off unused ports via sysfs kristen.c.accardi
2008-07-04 12:58 ` Jeff Garzik
@ 2008-07-11 13:50 ` Jeff Garzik
1 sibling, 0 replies; 5+ messages in thread
From: Jeff Garzik @ 2008-07-11 13:50 UTC (permalink / raw)
To: kristen.c.accardi; +Cc: linux-ide
kristen.c.accardi@intel.com wrote:
> This patch expands the definition of link power management to
> include the notion of simply powering the entire port off.
> We add a new valid value for link_power_management_policy:
>
> power_off: phy is not on at all.
> min_power: driver uses minimum possible power. hotplug
> may or may not be available.
> medium_power: best power/performance tradeoff. hotplug
> may or may not be available
> max_performance: max performance without regard to power
> hot plug is available.
>
> Additionally - this patch modifies the libata-core to
> power off the port automatically at init time if the
> driver marks the port as not hotpluggable.
>
> The user may not power off a port if it is occupied.
> If the port is powered off, and a new drive is plugged
> in, the drive will not be detected until the port is
> powered back up by setting the link_power_management_policy
> to "max_performance".
>
> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
> ---
> drivers/ata/libata-core.c | 58 +++++++++++++++++++++++++++++++++++++++++++++-
> drivers/ata/libata-scsi.c | 1
> include/linux/libata.h | 2 +
> 3 files changed, 60 insertions(+), 1 deletion(-)
>
> Index: linux-ahci-phy/drivers/ata/libata-core.c
> ===================================================================
> --- linux-ahci-phy.orig/drivers/ata/libata-core.c 2008-06-27 13:32:51.000000000 -0700
> +++ linux-ahci-phy/drivers/ata/libata-core.c 2008-07-01 16:33:00.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
> @@ -953,6 +966,7 @@ static int ata_dev_set_dipm(struct ata_d
> * disallow all transitions which effectively
> * disable DIPM anyway.
> */
> + default:
> break;
> }
>
> @@ -980,6 +994,22 @@ void ata_dev_enable_pm(struct ata_device
> int rc = 0;
> struct ata_port *ap = dev->link->ap;
>
> + /*
> + * if we don't have a device attached, all we can
> + * do is power off
> + */
> + if (!ata_dev_enabled(dev) && policy == POWER_OFF) {
> + ap->flags |= ATA_FLAG_NO_HOTPLUG;
> + ata_phy_offline(&ap->link);
> + goto enable_pm_out;
> + }
> +
> + /*
> + * if there's no device attached, we are done
> + */
> + if (!ata_dev_enabled(dev))
> + return;
> +
> /* set HIPM first, then DIPM */
> if (ap->ops->enable_pm)
> rc = ap->ops->enable_pm(ap, policy);
> @@ -1020,10 +1050,24 @@ static void ata_dev_disable_pm(struct at
>
> void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy)
> {
> - ap->pm_policy = policy;
> ap->link.eh_info.action |= ATA_EH_LPM;
> +
> + /*
> + * if we are coming from a state of OFF to ON, we need
> + * to reset the link and scan for devices in case someone
> + * plugged something in while we were off.
> + * Clear the NO_HOTPLUG flag because we are leaving the
> + * phy on now.
> + */
> + if (ap->pm_policy == POWER_OFF && policy != POWER_OFF) {
> + ap->flags &= ~ATA_FLAG_NO_HOTPLUG;
> + ap->link.eh_info.probe_mask |= ATA_ALL_DEVICES;
> + ap->link.eh_info.flags |= ATA_EH_RESET;
> + }
> ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY;
> + ap->pm_policy = policy;
> ata_port_schedule_eh(ap);
> + ata_port_wait_eh(ap);
> }
>
> #ifdef CONFIG_PM
just a question... why wait for EH?
> @@ -2678,6 +2722,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);
> }
>
> /**
do we really want to unconditionally assume SATA here?
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-07-11 13:50 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20080702225743.518230210@intel.com>
2008-07-02 23:14 ` [patch 1/2] allow user to power off unused ports via sysfs kristen.c.accardi
2008-07-04 12:58 ` Jeff Garzik
2008-07-11 13:50 ` Jeff Garzik
2008-07-02 23:14 ` [patch 2/2] set default of ahci driver to power off unused ports kristen.c.accardi
2008-07-04 13:02 ` Jeff Garzik
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).