Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09c5b480 authored by Gabriele Mazzotta's avatar Gabriele Mazzotta Committed by Tejun Heo
Browse files

libata: Ignore spurious PHY event on LPM policy change

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: default avatarGabriele Mazzotta <gabriele.mzt@gmail.com>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Cc: stable@vger.kernel.org
parent 8393b811
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -6766,8 +6766,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);

+3 −0
Original line number Diff line number Diff line
@@ -3597,6 +3597,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:
+9 −0
Original line number Diff line number Diff line
@@ -205,6 +205,7 @@ enum {
	ATA_LFLAG_SW_ACTIVITY	= (1 << 7), /* keep activity stats */
	ATA_LFLAG_NO_LPM	= (1 << 8), /* disable LPM on this link */
	ATA_LFLAG_RST_ONCE	= (1 << 9), /* limit recovery to one reset */
	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 */
@@ -309,6 +310,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,
@@ -788,6 +795,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])