Skip to content

Commit 0060bee

Browse files
committed
ata: libata-sata: Add link_power_management_supported sysfs attribute
A port link power management (LPM) policy can be controlled using the link_power_management_policy sysfs host attribute. However, this attribute exists also for hosts that do not support LPM and in such case, attempting to change the LPM policy for the host (port) will fail with -EOPNOTSUPP. Introduce the new sysfs link_power_management_supported host attribute to indicate to the user if a the port and the devices connected to the port for the host support LPM, which implies that the link_power_management_policy attribute can be used. Since checking that a port and its devices support LPM is common between the new ata_scsi_lpm_supported_show() function and the existing ata_scsi_lpm_store() function, the new helper ata_scsi_lpm_supported() is introduced. Fixes: 413e800 ("ata: libata-sata: Disallow changing LPM state if not supported") Reported-by: Borah, Chaitanya Kumar <[email protected]> Reported-by: kernel test robot <[email protected]> Closes: https://lore.kernel.org/oe-lkp/[email protected] Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]>
1 parent d2be9ea commit 0060bee

File tree

4 files changed

+44
-12
lines changed

4 files changed

+44
-12
lines changed

drivers/ata/ata_piix.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,7 @@ static struct ata_port_operations ich_pata_ops = {
10891089
};
10901090

10911091
static struct attribute *piix_sidpr_shost_attrs[] = {
1092+
&dev_attr_link_power_management_supported.attr,
10921093
&dev_attr_link_power_management_policy.attr,
10931094
NULL
10941095
};

drivers/ata/libahci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
111111
static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
112112

113113
static struct attribute *ahci_shost_attrs[] = {
114+
&dev_attr_link_power_management_supported.attr,
114115
&dev_attr_link_power_management_policy.attr,
115116
&dev_attr_em_message_type.attr,
116117
&dev_attr_em_message.attr,

drivers/ata/libata-sata.c

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -900,14 +900,52 @@ static const char *ata_lpm_policy_names[] = {
900900
[ATA_LPM_MIN_POWER] = "min_power",
901901
};
902902

903+
/*
904+
* Check if a port supports link power management.
905+
* Must be called with the port locked.
906+
*/
907+
static bool ata_scsi_lpm_supported(struct ata_port *ap)
908+
{
909+
struct ata_link *link;
910+
struct ata_device *dev;
911+
912+
if (ap->flags & ATA_FLAG_NO_LPM)
913+
return false;
914+
915+
ata_for_each_link(link, ap, EDGE) {
916+
ata_for_each_dev(dev, &ap->link, ENABLED) {
917+
if (dev->quirks & ATA_QUIRK_NOLPM)
918+
return false;
919+
}
920+
}
921+
922+
return true;
923+
}
924+
925+
static ssize_t ata_scsi_lpm_supported_show(struct device *dev,
926+
struct device_attribute *attr, char *buf)
927+
{
928+
struct Scsi_Host *shost = class_to_shost(dev);
929+
struct ata_port *ap = ata_shost_to_port(shost);
930+
unsigned long flags;
931+
bool supported;
932+
933+
spin_lock_irqsave(ap->lock, flags);
934+
supported = ata_scsi_lpm_supported(ap);
935+
spin_unlock_irqrestore(ap->lock, flags);
936+
937+
return sysfs_emit(buf, "%d\n", supported);
938+
}
939+
DEVICE_ATTR(link_power_management_supported, S_IRUGO,
940+
ata_scsi_lpm_supported_show, NULL);
941+
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_supported);
942+
903943
static ssize_t ata_scsi_lpm_store(struct device *device,
904944
struct device_attribute *attr,
905945
const char *buf, size_t count)
906946
{
907947
struct Scsi_Host *shost = class_to_shost(device);
908948
struct ata_port *ap = ata_shost_to_port(shost);
909-
struct ata_link *link;
910-
struct ata_device *dev;
911949
enum ata_lpm_policy policy;
912950
unsigned long flags;
913951

@@ -924,20 +962,11 @@ static ssize_t ata_scsi_lpm_store(struct device *device,
924962

925963
spin_lock_irqsave(ap->lock, flags);
926964

927-
if (ap->flags & ATA_FLAG_NO_LPM) {
965+
if (!ata_scsi_lpm_supported(ap)) {
928966
count = -EOPNOTSUPP;
929967
goto out_unlock;
930968
}
931969

932-
ata_for_each_link(link, ap, EDGE) {
933-
ata_for_each_dev(dev, &ap->link, ENABLED) {
934-
if (dev->quirks & ATA_QUIRK_NOLPM) {
935-
count = -EOPNOTSUPP;
936-
goto out_unlock;
937-
}
938-
}
939-
}
940-
941970
ap->target_lpm_policy = policy;
942971
ata_port_schedule_eh(ap);
943972
out_unlock:

include/linux/libata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes)
545545

546546
extern struct device_attribute dev_attr_unload_heads;
547547
#ifdef CONFIG_SATA_HOST
548+
extern struct device_attribute dev_attr_link_power_management_supported;
548549
extern struct device_attribute dev_attr_link_power_management_policy;
549550
extern struct device_attribute dev_attr_ncq_prio_supported;
550551
extern struct device_attribute dev_attr_ncq_prio_enable;

0 commit comments

Comments
 (0)