]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
libata: Add new med_power_with_dipm link_power_management_policy setting
authorHans de Goede <hdegoede@redhat.com>
Thu, 14 Sep 2017 10:35:36 +0000 (12:35 +0200)
committerTejun Heo <tj@kernel.org>
Tue, 19 Sep 2017 03:22:04 +0000 (20:22 -0700)
As described by Matthew Garret quite a while back:
https://mjg59.dreamwidth.org/34868.html

Intel CPUs starting with the Haswell generation need SATA links to power
down for the "package" part of the CPU to reach low power-states like
PC7 / P8 which bring a significant power-saving with them.

The default max_performance lpm policy does not allow for these high
PC states, both the medium_power and min_power policies do allow this.

The min_power policy saves significantly more power, but there are some
reports of some disks / SSDs not liking min_power leading to system
crashes and in some cases even data corruption has been reported.

Matthew has found a document documenting the default settings of
Intel's IRST Windows driver with which most laptops ship:
https://www-ssl.intel.com/content/dam/doc/reference-guide/sata-devices-implementation-recommendations.pdf

Matthew wrote a patch changing med_power to match those defaults, but
that never got anywhere as some people where reporting issues with the
patch-set that patch was a part of.

This commit is another attempt to make the default IRST driver settings
available under Linux, but instead of changing medium_power and
potentially introducing regressions, this commit adds a new
med_power_with_dipm setting which is identical to the existing
medium_power accept that it enables dipm on top, which makes it match
the Windows IRST driver settings, which should hopefully be safe to
use on most devices.

The med_power_with_dipm setting is close to min_power, except that:
a) It does not use host-initiated slumber mode (ASP not set),
   but it does allow device-initiated slumber
b) It does not enable DevSlp mode

On my T440s test laptop I get the following power savings when idle:
medium_power 0.9W
med_power_with_dipm 1.2W
min_power 1.2W

Suggested-by: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
include/linux/libata.h

index ee4c1ec9dca0ef9e51f4abf56924aab2112d9f77..65f7574afc554638a04524415abd388d5769f875 100644 (file)
@@ -3964,6 +3964,7 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
                scontrol &= ~(0x1 << 8);
                scontrol |= (0x6 << 8);
                break;
+       case ATA_LPM_MED_POWER_WITH_DIPM:
        case ATA_LPM_MIN_POWER:
                if (ata_link_nr_enabled(link) > 0)
                        /* no restrictions on LPM transitions */
index e4effef0c83f2bcea57bf5dda123b1c8ce4ed939..49b3745d2c1fecd5d0b2bd717f13dc546d1d3d0d 100644 (file)
@@ -3454,9 +3454,9 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev)
  *     @r_failed_dev: out parameter for failed device
  *
  *     Enable SATA Interface power management.  This will enable
- *     Device Interface Power Management (DIPM) for min_power
- *     policy, and then call driver specific callbacks for
- *     enabling Host Initiated Power management.
+ *     Device Interface Power Management (DIPM) for min_power and
+ *     medium_power_with_dipm policies, and then call driver specific
+ *     callbacks for enabling Host Initiated Power management.
  *
  *     LOCKING:
  *     EH context.
@@ -3502,7 +3502,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
                        hints &= ~ATA_LPM_HIPM;
 
                /* disable DIPM before changing link config */
-               if (policy != ATA_LPM_MIN_POWER && dipm) {
+               if (policy < ATA_LPM_MED_POWER_WITH_DIPM && dipm) {
                        err_mask = ata_dev_set_feature(dev,
                                        SETFEATURES_SATA_DISABLE, SATA_DIPM);
                        if (err_mask && err_mask != AC_ERR_DEV) {
@@ -3545,7 +3545,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
 
        /* host config updated, enable DIPM if transitioning to MIN_POWER */
        ata_for_each_dev(dev, link, ENABLED) {
-               if (policy == ATA_LPM_MIN_POWER && !no_dipm &&
+               if (policy >= ATA_LPM_MED_POWER_WITH_DIPM && !no_dipm &&
                    ata_id_has_dipm(dev->id)) {
                        err_mask = ata_dev_set_feature(dev,
                                        SETFEATURES_SATA_ENABLE, SATA_DIPM);
index 44ba292f2cd793f07e279ada3b2c83c44578f0cf..673e72f438eb738475acd997be2c04c52b464b22 100644 (file)
@@ -106,10 +106,11 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
 };
 
 static const char *ata_lpm_policy_names[] = {
-       [ATA_LPM_UNKNOWN]       = "max_performance",
-       [ATA_LPM_MAX_POWER]     = "max_performance",
-       [ATA_LPM_MED_POWER]     = "medium_power",
-       [ATA_LPM_MIN_POWER]     = "min_power",
+       [ATA_LPM_UNKNOWN]               = "max_performance",
+       [ATA_LPM_MAX_POWER]             = "max_performance",
+       [ATA_LPM_MED_POWER]             = "medium_power",
+       [ATA_LPM_MED_POWER_WITH_DIPM]   = "med_power_with_dipm",
+       [ATA_LPM_MIN_POWER]             = "min_power",
 };
 
 static ssize_t ata_scsi_lpm_store(struct device *device,
index 931c32f1f18d38835425eb21a4c952e1195e4f10..ed9826b21c5e8ad0f7e944f8be4c72915f93881e 100644 (file)
@@ -522,6 +522,7 @@ enum ata_lpm_policy {
        ATA_LPM_UNKNOWN,
        ATA_LPM_MAX_POWER,
        ATA_LPM_MED_POWER,
+       ATA_LPM_MED_POWER_WITH_DIPM, /* Med power + DIPM as win IRST does */
        ATA_LPM_MIN_POWER,
 };