aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/libata-core.c41
-rw-r--r--include/linux/libata.h1
2 files changed, 42 insertions, 0 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 3c5965d56c47..9fbf0595f3d4 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2232,6 +2232,40 @@ retry:
2232 return rc; 2232 return rc;
2233} 2233}
2234 2234
2235static int ata_do_link_spd_horkage(struct ata_device *dev)
2236{
2237 struct ata_link *plink = ata_dev_phys_link(dev);
2238 u32 target, target_limit;
2239
2240 if (!sata_scr_valid(plink))
2241 return 0;
2242
2243 if (dev->horkage & ATA_HORKAGE_1_5_GBPS)
2244 target = 1;
2245 else
2246 return 0;
2247
2248 target_limit = (1 << target) - 1;
2249
2250 /* if already on stricter limit, no need to push further */
2251 if (plink->sata_spd_limit <= target_limit)
2252 return 0;
2253
2254 plink->sata_spd_limit = target_limit;
2255
2256 /* Request another EH round by returning -EAGAIN if link is
2257 * going faster than the target speed. Forward progress is
2258 * guaranteed by setting sata_spd_limit to target_limit above.
2259 */
2260 if (plink->sata_spd > target) {
2261 ata_dev_printk(dev, KERN_INFO,
2262 "applying link speed limit horkage to %s\n",
2263 sata_spd_string(target));
2264 return -EAGAIN;
2265 }
2266 return 0;
2267}
2268
2235static inline u8 ata_dev_knobble(struct ata_device *dev) 2269static inline u8 ata_dev_knobble(struct ata_device *dev)
2236{ 2270{
2237 struct ata_port *ap = dev->link->ap; 2271 struct ata_port *ap = dev->link->ap;
@@ -2322,6 +2356,10 @@ int ata_dev_configure(struct ata_device *dev)
2322 return 0; 2356 return 0;
2323 } 2357 }
2324 2358
2359 rc = ata_do_link_spd_horkage(dev);
2360 if (rc)
2361 return rc;
2362
2325 /* let ACPI work its magic */ 2363 /* let ACPI work its magic */
2326 rc = ata_acpi_on_devcfg(dev); 2364 rc = ata_acpi_on_devcfg(dev);
2327 if (rc) 2365 if (rc)
@@ -4223,6 +4261,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
4223 /* Devices that do not need bridging limits applied */ 4261 /* Devices that do not need bridging limits applied */
4224 { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, }, 4262 { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, },
4225 4263
4264 /* Devices which aren't very happy with higher link speeds */
4265 { "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS, },
4266
4226 /* End Marker */ 4267 /* End Marker */
4227 { } 4268 { }
4228}; 4269};
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 9dcefee5843c..5d87bc09a1f5 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -380,6 +380,7 @@ enum {
380 ATA_HORKAGE_ATAPI_MOD16_DMA = (1 << 11), /* use ATAPI DMA for commands 380 ATA_HORKAGE_ATAPI_MOD16_DMA = (1 << 11), /* use ATAPI DMA for commands
381 not multiple of 16 bytes */ 381 not multiple of 16 bytes */
382 ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firwmare update warning */ 382 ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firwmare update warning */
383 ATA_HORKAGE_1_5_GBPS = (1 << 13), /* force 1.5 Gbps */
383 384
384 /* DMA mask for user DMA control: User visible values; DO NOT 385 /* DMA mask for user DMA control: User visible values; DO NOT
385 renumber */ 386 renumber */