libata: add @spd_limit to sata_down_spd_limit()
Add @spd_limit to sata_down_spd_limit() so that the caller can specify the SPD limit it wants. This parameter doesn't get in the way even when it's too low. The closest possible limit is applied. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
parent
99cf610aa4
commit
a07d499b47
@ -2777,7 +2777,7 @@ int ata_bus_probe(struct ata_port *ap)
|
|||||||
/* This is the last chance, better to slow
|
/* This is the last chance, better to slow
|
||||||
* down than lose it.
|
* down than lose it.
|
||||||
*/
|
*/
|
||||||
sata_down_spd_limit(&ap->link);
|
sata_down_spd_limit(&ap->link, 0);
|
||||||
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
|
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2873,21 +2873,27 @@ void ata_port_disable(struct ata_port *ap)
|
|||||||
/**
|
/**
|
||||||
* sata_down_spd_limit - adjust SATA spd limit downward
|
* sata_down_spd_limit - adjust SATA spd limit downward
|
||||||
* @link: Link to adjust SATA spd limit for
|
* @link: Link to adjust SATA spd limit for
|
||||||
|
* @spd_limit: Additional limit
|
||||||
*
|
*
|
||||||
* Adjust SATA spd limit of @link downward. Note that this
|
* Adjust SATA spd limit of @link downward. Note that this
|
||||||
* function only adjusts the limit. The change must be applied
|
* function only adjusts the limit. The change must be applied
|
||||||
* using sata_set_spd().
|
* 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:
|
* LOCKING:
|
||||||
* Inherited from caller.
|
* Inherited from caller.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
* 0 on success, negative errno on failure
|
* 0 on success, negative errno on failure
|
||||||
*/
|
*/
|
||||||
int sata_down_spd_limit(struct ata_link *link)
|
int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
|
||||||
{
|
{
|
||||||
u32 sstatus, spd, mask;
|
u32 sstatus, spd, mask;
|
||||||
int rc, highbit;
|
int rc, bit;
|
||||||
|
|
||||||
if (!sata_scr_valid(link))
|
if (!sata_scr_valid(link))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
@ -2906,8 +2912,8 @@ int sata_down_spd_limit(struct ata_link *link)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* unconditionally mask off the highest bit */
|
/* unconditionally mask off the highest bit */
|
||||||
highbit = fls(mask) - 1;
|
bit = fls(mask) - 1;
|
||||||
mask &= ~(1 << highbit);
|
mask &= ~(1 << bit);
|
||||||
|
|
||||||
/* Mask off all speeds higher than or equal to the current
|
/* Mask off all speeds higher than or equal to the current
|
||||||
* one. Force 1.5Gbps if current SPD is not available.
|
* one. Force 1.5Gbps if current SPD is not available.
|
||||||
@ -2921,6 +2927,15 @@ int sata_down_spd_limit(struct ata_link *link)
|
|||||||
if (!mask)
|
if (!mask)
|
||||||
return -EINVAL;
|
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;
|
link->sata_spd_limit = mask;
|
||||||
|
|
||||||
ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
|
ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
|
||||||
|
@ -1875,7 +1875,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev,
|
|||||||
/* speed down? */
|
/* speed down? */
|
||||||
if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
|
if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
|
||||||
/* speed down SATA link speed if possible */
|
/* speed down SATA link speed if possible */
|
||||||
if (sata_down_spd_limit(link) == 0) {
|
if (sata_down_spd_limit(link, 0) == 0) {
|
||||||
action |= ATA_EH_RESET;
|
action |= ATA_EH_RESET;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -2627,11 +2627,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (try == max_tries - 1) {
|
if (try == max_tries - 1) {
|
||||||
sata_down_spd_limit(link);
|
sata_down_spd_limit(link, 0);
|
||||||
if (slave)
|
if (slave)
|
||||||
sata_down_spd_limit(slave);
|
sata_down_spd_limit(slave, 0);
|
||||||
} else if (rc == -EPIPE)
|
} else if (rc == -EPIPE)
|
||||||
sata_down_spd_limit(failed_link);
|
sata_down_spd_limit(failed_link, 0);
|
||||||
|
|
||||||
if (hardreset)
|
if (hardreset)
|
||||||
reset = hardreset;
|
reset = hardreset;
|
||||||
@ -3011,7 +3011,7 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
|
|||||||
/* This is the last chance, better to slow
|
/* This is the last chance, better to slow
|
||||||
* down than lose it.
|
* down than lose it.
|
||||||
*/
|
*/
|
||||||
sata_down_spd_limit(ata_dev_phys_link(dev));
|
sata_down_spd_limit(ata_dev_phys_link(dev), 0);
|
||||||
if (dev->pio_mode > XFER_PIO_0)
|
if (dev->pio_mode > XFER_PIO_0)
|
||||||
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
|
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
|
||||||
}
|
}
|
||||||
|
@ -729,7 +729,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
|
|||||||
if (tries) {
|
if (tries) {
|
||||||
/* consecutive revalidation failures? speed down */
|
/* consecutive revalidation failures? speed down */
|
||||||
if (reval_failed)
|
if (reval_failed)
|
||||||
sata_down_spd_limit(link);
|
sata_down_spd_limit(link, 0);
|
||||||
else
|
else
|
||||||
reval_failed = 1;
|
reval_failed = 1;
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
|
|||||||
extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
|
extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
|
||||||
unsigned int readid_flags);
|
unsigned int readid_flags);
|
||||||
extern int ata_dev_configure(struct ata_device *dev);
|
extern int ata_dev_configure(struct ata_device *dev);
|
||||||
extern int sata_down_spd_limit(struct ata_link *link);
|
extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
|
||||||
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
|
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
|
||||||
extern void ata_sg_clean(struct ata_queued_cmd *qc);
|
extern void ata_sg_clean(struct ata_queued_cmd *qc);
|
||||||
extern void ata_qc_free(struct ata_queued_cmd *qc);
|
extern void ata_qc_free(struct ata_queued_cmd *qc);
|
||||||
|
Loading…
Reference in New Issue
Block a user