From 6abad7ba984494337083c54507de46c38900e179 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Wed, 27 May 2009 15:04:43 +0800 Subject: [PATCH] [libata] ahci: Restore SB600 SATA controller 64 bit DMA Community reported one SB600 SATA issue(BZ #9412), which led to 64 bit DMA disablement for all SB600 revisions by driver maintainers with commits 86c9f576a6259148c254d54db3350ef8bf43e270 and f2499916f390228689961d62c2aadb15d6f2f4e3. But the root cause is ASUS M2A-VM system BIOS bug in old revisions like 0901, while forcing into 32bit DMA happens to work as workaround. Now it's time to withdraw f2499916f390228689961d62c2aadb15d6f2f4e3 so as to restore the SB600 SATA 64bit DMA capability. This patch is also adding the workaround for M2A-VM old BIOS revisions, but users are suggested to upgrade their system BIOS to the latest one if they meet this issue. Signed-off-by: Shane Huang Cc: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 52 +++++++++++++++++++++++++++++++++++-- drivers/firmware/dmi_scan.c | 1 + 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 2141a31f176be..15a23031833f4 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -431,8 +431,7 @@ static const struct ata_port_info ahci_port_info[] = { [board_ahci_sb600] = { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | - AHCI_HFLAG_SECT255), + AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255), .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, @@ -2585,6 +2584,51 @@ static void ahci_p5wdh_workaround(struct ata_host *host) } } +/* + * SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older + * BIOS. The oldest version known to be broken is 0901 and working is + * 1501 which was released on 2007-10-26. Force 32bit DMA on anything + * older than 1501. Please read bko#9412 for more info. + */ +static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) +{ + static const struct dmi_system_id sysids[] = { + { + .ident = "ASUS M2A-VM", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"), + }, + }, + { } + }; + const char *cutoff_mmdd = "10/26"; + const char *date; + int year; + + if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) || + !dmi_check_system(sysids)) + return false; + + /* + * Argh.... both version and date are free form strings. + * Let's hope they're using the same date format across + * different versions. + */ + date = dmi_get_system_info(DMI_BIOS_DATE); + year = dmi_get_year(DMI_BIOS_DATE); + if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' && + (year > 2007 || + (year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0))) + return false; + + dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, " + "forcing 32bit DMA, update BIOS\n"); + + return true; +} + static bool ahci_broken_system_poweroff(struct pci_dev *pdev) { static const struct dmi_system_id broken_systems[] = { @@ -2745,6 +2789,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; + /* apply ASUS M2A_VM quirk */ + if (ahci_asus_m2a_vm_32bit_only(pdev)) + hpriv->flags |= AHCI_HFLAG_32BIT_ONLY; + if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) pci_enable_msi(pdev); diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 5f1b5400d96ab..24c84ae81527b 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -596,6 +596,7 @@ int dmi_get_year(int field) return year; } +EXPORT_SYMBOL(dmi_get_year); /** * dmi_walk - Walk the DMI table and get called back for every record -- 2.39.5