diff options
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6b91c26a4635..15a23031833f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -77,8 +77,6 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, | |||
77 | size_t size); | 77 | size_t size); |
78 | static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, | 78 | static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, |
79 | ssize_t size); | 79 | ssize_t size); |
80 | #define MAX_SLOTS 8 | ||
81 | #define MAX_RETRY 15 | ||
82 | 80 | ||
83 | enum { | 81 | enum { |
84 | AHCI_PCI_BAR = 5, | 82 | AHCI_PCI_BAR = 5, |
@@ -231,6 +229,10 @@ enum { | |||
231 | 229 | ||
232 | ICH_MAP = 0x90, /* ICH MAP register */ | 230 | ICH_MAP = 0x90, /* ICH MAP register */ |
233 | 231 | ||
232 | /* em constants */ | ||
233 | EM_MAX_SLOTS = 8, | ||
234 | EM_MAX_RETRY = 5, | ||
235 | |||
234 | /* em_ctl bits */ | 236 | /* em_ctl bits */ |
235 | EM_CTL_RST = (1 << 9), /* Reset */ | 237 | EM_CTL_RST = (1 << 9), /* Reset */ |
236 | EM_CTL_TM = (1 << 8), /* Transmit Message */ | 238 | EM_CTL_TM = (1 << 8), /* Transmit Message */ |
@@ -282,8 +284,8 @@ struct ahci_port_priv { | |||
282 | unsigned int ncq_saw_dmas:1; | 284 | unsigned int ncq_saw_dmas:1; |
283 | unsigned int ncq_saw_sdb:1; | 285 | unsigned int ncq_saw_sdb:1; |
284 | u32 intr_mask; /* interrupts to enable */ | 286 | u32 intr_mask; /* interrupts to enable */ |
285 | struct ahci_em_priv em_priv[MAX_SLOTS];/* enclosure management info | 287 | /* enclosure management info per PM slot */ |
286 | * per PM slot */ | 288 | struct ahci_em_priv em_priv[EM_MAX_SLOTS]; |
287 | }; | 289 | }; |
288 | 290 | ||
289 | static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); | 291 | static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); |
@@ -313,7 +315,6 @@ static void ahci_error_handler(struct ata_port *ap); | |||
313 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); | 315 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); |
314 | static int ahci_port_resume(struct ata_port *ap); | 316 | static int ahci_port_resume(struct ata_port *ap); |
315 | static void ahci_dev_config(struct ata_device *dev); | 317 | static void ahci_dev_config(struct ata_device *dev); |
316 | static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); | ||
317 | static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, | 318 | static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, |
318 | u32 opts); | 319 | u32 opts); |
319 | #ifdef CONFIG_PM | 320 | #ifdef CONFIG_PM |
@@ -404,14 +405,14 @@ static struct ata_port_operations ahci_sb600_ops = { | |||
404 | #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) | 405 | #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) |
405 | 406 | ||
406 | static const struct ata_port_info ahci_port_info[] = { | 407 | static const struct ata_port_info ahci_port_info[] = { |
407 | /* board_ahci */ | 408 | [board_ahci] = |
408 | { | 409 | { |
409 | .flags = AHCI_FLAG_COMMON, | 410 | .flags = AHCI_FLAG_COMMON, |
410 | .pio_mask = ATA_PIO4, | 411 | .pio_mask = ATA_PIO4, |
411 | .udma_mask = ATA_UDMA6, | 412 | .udma_mask = ATA_UDMA6, |
412 | .port_ops = &ahci_ops, | 413 | .port_ops = &ahci_ops, |
413 | }, | 414 | }, |
414 | /* board_ahci_vt8251 */ | 415 | [board_ahci_vt8251] = |
415 | { | 416 | { |
416 | AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), | 417 | AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), |
417 | .flags = AHCI_FLAG_COMMON, | 418 | .flags = AHCI_FLAG_COMMON, |
@@ -419,7 +420,7 @@ static const struct ata_port_info ahci_port_info[] = { | |||
419 | .udma_mask = ATA_UDMA6, | 420 | .udma_mask = ATA_UDMA6, |
420 | .port_ops = &ahci_vt8251_ops, | 421 | .port_ops = &ahci_vt8251_ops, |
421 | }, | 422 | }, |
422 | /* board_ahci_ign_iferr */ | 423 | [board_ahci_ign_iferr] = |
423 | { | 424 | { |
424 | AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), | 425 | AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), |
425 | .flags = AHCI_FLAG_COMMON, | 426 | .flags = AHCI_FLAG_COMMON, |
@@ -427,17 +428,16 @@ static const struct ata_port_info ahci_port_info[] = { | |||
427 | .udma_mask = ATA_UDMA6, | 428 | .udma_mask = ATA_UDMA6, |
428 | .port_ops = &ahci_ops, | 429 | .port_ops = &ahci_ops, |
429 | }, | 430 | }, |
430 | /* board_ahci_sb600 */ | 431 | [board_ahci_sb600] = |
431 | { | 432 | { |
432 | AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | | 433 | AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | |
433 | AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | | 434 | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255), |
434 | AHCI_HFLAG_SECT255), | ||
435 | .flags = AHCI_FLAG_COMMON, | 435 | .flags = AHCI_FLAG_COMMON, |
436 | .pio_mask = ATA_PIO4, | 436 | .pio_mask = ATA_PIO4, |
437 | .udma_mask = ATA_UDMA6, | 437 | .udma_mask = ATA_UDMA6, |
438 | .port_ops = &ahci_sb600_ops, | 438 | .port_ops = &ahci_sb600_ops, |
439 | }, | 439 | }, |
440 | /* board_ahci_mv */ | 440 | [board_ahci_mv] = |
441 | { | 441 | { |
442 | AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | | 442 | AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | |
443 | AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP), | 443 | AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP), |
@@ -447,7 +447,7 @@ static const struct ata_port_info ahci_port_info[] = { | |||
447 | .udma_mask = ATA_UDMA6, | 447 | .udma_mask = ATA_UDMA6, |
448 | .port_ops = &ahci_ops, | 448 | .port_ops = &ahci_ops, |
449 | }, | 449 | }, |
450 | /* board_ahci_sb700, for SB700 and SB800 */ | 450 | [board_ahci_sb700] = /* for SB700 and SB800 */ |
451 | { | 451 | { |
452 | AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), | 452 | AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), |
453 | .flags = AHCI_FLAG_COMMON, | 453 | .flags = AHCI_FLAG_COMMON, |
@@ -455,7 +455,7 @@ static const struct ata_port_info ahci_port_info[] = { | |||
455 | .udma_mask = ATA_UDMA6, | 455 | .udma_mask = ATA_UDMA6, |
456 | .port_ops = &ahci_sb600_ops, | 456 | .port_ops = &ahci_sb600_ops, |
457 | }, | 457 | }, |
458 | /* board_ahci_mcp65 */ | 458 | [board_ahci_mcp65] = |
459 | { | 459 | { |
460 | AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), | 460 | AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), |
461 | .flags = AHCI_FLAG_COMMON, | 461 | .flags = AHCI_FLAG_COMMON, |
@@ -463,7 +463,7 @@ static const struct ata_port_info ahci_port_info[] = { | |||
463 | .udma_mask = ATA_UDMA6, | 463 | .udma_mask = ATA_UDMA6, |
464 | .port_ops = &ahci_ops, | 464 | .port_ops = &ahci_ops, |
465 | }, | 465 | }, |
466 | /* board_ahci_nopmp */ | 466 | [board_ahci_nopmp] = |
467 | { | 467 | { |
468 | AHCI_HFLAGS (AHCI_HFLAG_NO_PMP), | 468 | AHCI_HFLAGS (AHCI_HFLAG_NO_PMP), |
469 | .flags = AHCI_FLAG_COMMON, | 469 | .flags = AHCI_FLAG_COMMON, |
@@ -1141,12 +1141,12 @@ static void ahci_start_port(struct ata_port *ap) | |||
1141 | emp = &pp->em_priv[link->pmp]; | 1141 | emp = &pp->em_priv[link->pmp]; |
1142 | 1142 | ||
1143 | /* EM Transmit bit maybe busy during init */ | 1143 | /* EM Transmit bit maybe busy during init */ |
1144 | for (i = 0; i < MAX_RETRY; i++) { | 1144 | for (i = 0; i < EM_MAX_RETRY; i++) { |
1145 | rc = ahci_transmit_led_message(ap, | 1145 | rc = ahci_transmit_led_message(ap, |
1146 | emp->led_state, | 1146 | emp->led_state, |
1147 | 4); | 1147 | 4); |
1148 | if (rc == -EBUSY) | 1148 | if (rc == -EBUSY) |
1149 | udelay(100); | 1149 | msleep(1); |
1150 | else | 1150 | else |
1151 | break; | 1151 | break; |
1152 | } | 1152 | } |
@@ -1340,7 +1340,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, | |||
1340 | 1340 | ||
1341 | /* get the slot number from the message */ | 1341 | /* get the slot number from the message */ |
1342 | pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; | 1342 | pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; |
1343 | if (pmp < MAX_SLOTS) | 1343 | if (pmp < EM_MAX_SLOTS) |
1344 | emp = &pp->em_priv[pmp]; | 1344 | emp = &pp->em_priv[pmp]; |
1345 | else | 1345 | else |
1346 | return -EINVAL; | 1346 | return -EINVAL; |
@@ -1408,7 +1408,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, | |||
1408 | 1408 | ||
1409 | /* get the slot number from the message */ | 1409 | /* get the slot number from the message */ |
1410 | pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; | 1410 | pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; |
1411 | if (pmp < MAX_SLOTS) | 1411 | if (pmp < EM_MAX_SLOTS) |
1412 | emp = &pp->em_priv[pmp]; | 1412 | emp = &pp->em_priv[pmp]; |
1413 | else | 1413 | else |
1414 | return -EINVAL; | 1414 | return -EINVAL; |
@@ -2584,6 +2584,51 @@ static void ahci_p5wdh_workaround(struct ata_host *host) | |||
2584 | } | 2584 | } |
2585 | } | 2585 | } |
2586 | 2586 | ||
2587 | /* | ||
2588 | * SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older | ||
2589 | * BIOS. The oldest version known to be broken is 0901 and working is | ||
2590 | * 1501 which was released on 2007-10-26. Force 32bit DMA on anything | ||
2591 | * older than 1501. Please read bko#9412 for more info. | ||
2592 | */ | ||
2593 | static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) | ||
2594 | { | ||
2595 | static const struct dmi_system_id sysids[] = { | ||
2596 | { | ||
2597 | .ident = "ASUS M2A-VM", | ||
2598 | .matches = { | ||
2599 | DMI_MATCH(DMI_BOARD_VENDOR, | ||
2600 | "ASUSTeK Computer INC."), | ||
2601 | DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"), | ||
2602 | }, | ||
2603 | }, | ||
2604 | { } | ||
2605 | }; | ||
2606 | const char *cutoff_mmdd = "10/26"; | ||
2607 | const char *date; | ||
2608 | int year; | ||
2609 | |||
2610 | if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) || | ||
2611 | !dmi_check_system(sysids)) | ||
2612 | return false; | ||
2613 | |||
2614 | /* | ||
2615 | * Argh.... both version and date are free form strings. | ||
2616 | * Let's hope they're using the same date format across | ||
2617 | * different versions. | ||
2618 | */ | ||
2619 | date = dmi_get_system_info(DMI_BIOS_DATE); | ||
2620 | year = dmi_get_year(DMI_BIOS_DATE); | ||
2621 | if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' && | ||
2622 | (year > 2007 || | ||
2623 | (year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0))) | ||
2624 | return false; | ||
2625 | |||
2626 | dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, " | ||
2627 | "forcing 32bit DMA, update BIOS\n"); | ||
2628 | |||
2629 | return true; | ||
2630 | } | ||
2631 | |||
2587 | static bool ahci_broken_system_poweroff(struct pci_dev *pdev) | 2632 | static bool ahci_broken_system_poweroff(struct pci_dev *pdev) |
2588 | { | 2633 | { |
2589 | static const struct dmi_system_id broken_systems[] = { | 2634 | static const struct dmi_system_id broken_systems[] = { |
@@ -2744,6 +2789,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2744 | if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) | 2789 | if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) |
2745 | hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; | 2790 | hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; |
2746 | 2791 | ||
2792 | /* apply ASUS M2A_VM quirk */ | ||
2793 | if (ahci_asus_m2a_vm_32bit_only(pdev)) | ||
2794 | hpriv->flags |= AHCI_HFLAG_32BIT_ONLY; | ||
2795 | |||
2747 | if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) | 2796 | if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) |
2748 | pci_enable_msi(pdev); | 2797 | pci_enable_msi(pdev); |
2749 | 2798 | ||