diff options
author | Gabriele Mazzotta <gabriele.mzt@gmail.com> | 2015-04-25 19:52:37 +0200 |
---|---|---|
committer | Zefan Li <lizefan@huawei.com> | 2015-09-18 09:20:37 +0800 |
commit | 017fd99beb3ccdb301009fa8f905f574e3e3ce29 (patch) | |
tree | aedf3c10df99abe1e241568a011f5c310b4816a1 | |
parent | ba4e97b49e74a7b1c6283e3d4d6dbe0c72b991af (diff) | |
download | lwn-017fd99beb3ccdb301009fa8f905f574e3e3ce29.tar.gz lwn-017fd99beb3ccdb301009fa8f905f574e3e3ce29.zip |
libata: Ignore spurious PHY event on LPM policy change
commit 09c5b4803a80a5451d950d6a539d2eb311dc0fb1 upstream.
When the LPM policy is set to ATA_LPM_MAX_POWER, the device might
generate a spurious PHY event that cuases errors on the link.
Ignore this event if it occured within 10s after the policy change.
The timeout was chosen observing that on a Dell XPS13 9333 these
spurious events can occur up to roughly 6s after the policy change.
Link: http://lkml.kernel.org/g/3352987.ugV1Ipy7Z5@xps13
Signed-off-by: Gabriele Mazzotta <gabriele.mzt@gmail.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
[lizf: Backported to 3.4: adjust context]
Signed-off-by: Zefan Li <lizefan@huawei.com>
-rw-r--r-- | drivers/ata/libata-core.c | 15 | ||||
-rw-r--r-- | drivers/ata/libata-eh.c | 3 | ||||
-rw-r--r-- | include/linux/libata.h | 9 |
3 files changed, 26 insertions, 1 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index af96831e68b9..0a6767b9939c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6671,8 +6671,21 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, */ bool sata_lpm_ignore_phy_events(struct ata_link *link) { + unsigned long lpm_timeout = link->last_lpm_change + + msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY); + /* if LPM is enabled, PHYRDY doesn't mean anything */ - return !!(link->lpm_policy > ATA_LPM_MAX_POWER); + if (link->lpm_policy > ATA_LPM_MAX_POWER) + return true; + + /* ignore the first PHY event after the LPM policy changed + * as it is might be spurious + */ + if ((link->flags & ATA_LFLAG_CHANGED) && + time_before(jiffies, lpm_timeout)) + return true; + + return false; } EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 37fb4d6069a2..033b8cd497ac 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3424,6 +3424,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, } } + link->last_lpm_change = jiffies; + link->flags |= ATA_LFLAG_CHANGED; + return 0; fail: diff --git a/include/linux/libata.h b/include/linux/libata.h index 41608ba8f613..35e7f71cd8a5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -182,6 +182,7 @@ enum { ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ + ATA_LFLAG_CHANGED = (1 << 10), /* LPM state changed on this link */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ @@ -285,6 +286,12 @@ enum { */ ATA_TMOUT_PMP_SRST_WAIT = 5000, + /* When the LPM policy is set to ATA_LPM_MAX_POWER, there might + * be a spurious PHY event, so ignore the first PHY event that + * occurs within 10s after the policy change. + */ + ATA_TMOUT_SPURIOUS_PHY = 10000, + /* ATA bus states */ BUS_UNKNOWN = 0, BUS_DMA = 1, @@ -727,6 +734,8 @@ struct ata_link { struct ata_eh_context eh_context; struct ata_device device[ATA_MAX_DEVICES]; + + unsigned long last_lpm_change; /* when last LPM change happened */ }; #define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag) #define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0]) |