|
@@ -2232,6 +2232,40 @@ retry:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int ata_do_link_spd_horkage(struct ata_device *dev)
|
|
|
+{
|
|
|
+ struct ata_link *plink = ata_dev_phys_link(dev);
|
|
|
+ u32 target, target_limit;
|
|
|
+
|
|
|
+ if (!sata_scr_valid(plink))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (dev->horkage & ATA_HORKAGE_1_5_GBPS)
|
|
|
+ target = 1;
|
|
|
+ else
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ target_limit = (1 << target) - 1;
|
|
|
+
|
|
|
+ /* if already on stricter limit, no need to push further */
|
|
|
+ if (plink->sata_spd_limit <= target_limit)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ plink->sata_spd_limit = target_limit;
|
|
|
+
|
|
|
+ /* Request another EH round by returning -EAGAIN if link is
|
|
|
+ * going faster than the target speed. Forward progress is
|
|
|
+ * guaranteed by setting sata_spd_limit to target_limit above.
|
|
|
+ */
|
|
|
+ if (plink->sata_spd > target) {
|
|
|
+ ata_dev_printk(dev, KERN_INFO,
|
|
|
+ "applying link speed limit horkage to %s\n",
|
|
|
+ sata_spd_string(target));
|
|
|
+ return -EAGAIN;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static inline u8 ata_dev_knobble(struct ata_device *dev)
|
|
|
{
|
|
|
struct ata_port *ap = dev->link->ap;
|
|
@@ -2322,6 +2356,10 @@ int ata_dev_configure(struct ata_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ rc = ata_do_link_spd_horkage(dev);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
/* let ACPI work its magic */
|
|
|
rc = ata_acpi_on_devcfg(dev);
|
|
|
if (rc)
|
|
@@ -4223,6 +4261,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
|
|
|
/* Devices that do not need bridging limits applied */
|
|
|
{ "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, },
|
|
|
|
|
|
+ /* Devices which aren't very happy with higher link speeds */
|
|
|
+ { "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS, },
|
|
|
+
|
|
|
/* End Marker */
|
|
|
{ }
|
|
|
};
|