diff options
author | Damien Le Moal <dlemoal@kernel.org> | 2024-07-17 17:39:29 +0900 |
---|---|---|
committer | Damien Le Moal <dlemoal@kernel.org> | 2024-09-07 10:16:55 +0900 |
commit | b642212d8858059f652b2a81b0cb73541416d2e3 (patch) | |
tree | 7a8f549e74289bc6ed3ec3ed696268eb50374630 /drivers/ata/libata-sata.c | |
parent | 5bb52d926598a018b1510fd6684dcbaed31d57f2 (diff) |
ata: libata: Move sata_down_spd_limit() to libata-sata.c
Move the definition of the function sata_down_spd_limit() to
libata-sata.c where it belongs, together with sata_set_spd().
The helper function ata_sstatus_online() is also changed to be an
inline function defined in drivers/ata/libata.h.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Diffstat (limited to 'drivers/ata/libata-sata.c')
-rw-r--r-- | drivers/ata/libata-sata.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index ea6126c139af..124e2b2ea3c0 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -518,6 +518,86 @@ int sata_set_spd(struct ata_link *link) EXPORT_SYMBOL_GPL(sata_set_spd); /** + * sata_down_spd_limit - adjust SATA spd limit downward + * @link: Link to adjust SATA spd limit for + * @spd_limit: Additional limit + * + * Adjust SATA spd limit of @link downward. Note that this + * function only adjusts the limit. The change must be applied + * using sata_set_spd(). + * + * If @spd_limit is non-zero, the speed is limited to equal to or + * lower than @spd_limit if such speed is supported. If + * @spd_limit is slower than any supported speed, only the lowest + * supported speed is allowed. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * 0 on success, negative errno on failure + */ +int sata_down_spd_limit(struct ata_link *link, u32 spd_limit) +{ + u32 sstatus, spd, mask; + int rc, bit; + + if (!sata_scr_valid(link)) + return -EOPNOTSUPP; + + /* If SCR can be read, use it to determine the current SPD. + * If not, use cached value in link->sata_spd. + */ + rc = sata_scr_read(link, SCR_STATUS, &sstatus); + if (rc == 0 && ata_sstatus_online(sstatus)) + spd = (sstatus >> 4) & 0xf; + else + spd = link->sata_spd; + + mask = link->sata_spd_limit; + if (mask <= 1) + return -EINVAL; + + /* unconditionally mask off the highest bit */ + bit = fls(mask) - 1; + mask &= ~(1 << bit); + + /* + * Mask off all speeds higher than or equal to the current one. At + * this point, if current SPD is not available and we previously + * recorded the link speed from SStatus, the driver has already + * masked off the highest bit so mask should already be 1 or 0. + * Otherwise, we should not force 1.5Gbps on a link where we have + * not previously recorded speed from SStatus. Just return in this + * case. + */ + if (spd > 1) + mask &= (1 << (spd - 1)) - 1; + else if (link->sata_spd) + return -EINVAL; + + /* were we already at the bottom? */ + if (!mask) + return -EINVAL; + + if (spd_limit) { + if (mask & ((1 << spd_limit) - 1)) + mask &= (1 << spd_limit) - 1; + else { + bit = ffs(mask) - 1; + mask = 1 << bit; + } + } + + link->sata_spd_limit = mask; + + ata_link_warn(link, "limiting SATA link speed to %s\n", + sata_spd_string(fls(mask))); + + return 0; +} + +/** * sata_link_hardreset - reset link via SATA phy reset * @link: link to reset * @timing: timing parameters { interval, duration, timeout } in msec |