diff options
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 209 |
1 files changed, 159 insertions, 50 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index acd1162..a3241a1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -122,6 +122,7 @@ enum { HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ HOST_EM_LOC = 0x1c, /* Enclosure Management location */ HOST_EM_CTL = 0x20, /* Enclosure Management Control */ + HOST_CAP2 = 0x24, /* host capabilities, extended */ /* HOST_CTL bits */ HOST_RESET = (1 << 0), /* reset controller; self-clear */ @@ -129,16 +130,29 @@ enum { HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ /* HOST_CAP bits */ + HOST_CAP_SXS = (1 << 5), /* Supports External SATA */ HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */ - HOST_CAP_SSC = (1 << 14), /* Slumber capable */ + HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */ + HOST_CAP_PART = (1 << 13), /* Partial state capable */ + HOST_CAP_SSC = (1 << 14), /* Slumber state capable */ + HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */ + HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */ HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ + HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */ HOST_CAP_CLO = (1 << 24), /* Command List Override support */ + HOST_CAP_LED = (1 << 25), /* Supports activity LED */ HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ + HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */ HOST_CAP_SNTF = (1 << 29), /* SNotification register */ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ + /* HOST_CAP2 bits */ + HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */ + HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */ + HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */ + /* registers for each SATA port */ PORT_LST_ADDR = 0x00, /* command list DMA addr */ PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ @@ -267,8 +281,10 @@ struct ahci_em_priv { struct ahci_host_priv { unsigned int flags; /* AHCI_HFLAG_* */ u32 cap; /* cap to use */ + u32 cap2; /* cap2 to use */ u32 port_map; /* port map to use */ u32 saved_cap; /* saved initial cap */ + u32 saved_cap2; /* saved initial cap2 */ u32 saved_port_map; /* saved initial port_map */ u32 em_loc; /* enclosure management location */ }; @@ -331,12 +347,15 @@ static void ahci_init_sw_activity(struct ata_link *link); static ssize_t ahci_show_host_caps(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t ahci_show_host_cap2(struct device *dev, + struct device_attribute *attr, char *buf); static ssize_t ahci_show_host_version(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t ahci_show_port_cmd(struct device *dev, struct device_attribute *attr, char *buf); DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); +DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); @@ -345,6 +364,7 @@ static struct device_attribute *ahci_shost_attrs[] = { &dev_attr_em_message_type, &dev_attr_em_message, &dev_attr_ahci_host_caps, + &dev_attr_ahci_host_cap2, &dev_attr_ahci_host_version, &dev_attr_ahci_port_cmd, NULL @@ -447,7 +467,8 @@ static const struct ata_port_info ahci_port_info[] = { [board_ahci_sb600] = { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255), + AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 | + AHCI_HFLAG_32BIT_ONLY), .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, @@ -554,7 +575,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */ /* AMD */ - { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD SB900 */ + { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */ /* AMD is using RAID class only for ahci controllers */ { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci }, @@ -584,6 +605,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq }, /* Linux ID */ { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq }, /* MCP73 */ { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq }, /* MCP73 */ { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq }, /* MCP73 */ @@ -732,6 +754,16 @@ static ssize_t ahci_show_host_caps(struct device *dev, return sprintf(buf, "%x\n", hpriv->cap); } +static ssize_t ahci_show_host_cap2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ahci_host_priv *hpriv = ap->host->private_data; + + return sprintf(buf, "%x\n", hpriv->cap2); +} + static ssize_t ahci_show_host_version(struct device *dev, struct device_attribute *attr, char *buf) { @@ -771,7 +803,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, struct ahci_host_priv *hpriv) { void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; - u32 cap, port_map; + u32 cap, cap2, vers, port_map; int i; int mv; @@ -784,6 +816,14 @@ static void ahci_save_initial_config(struct pci_dev *pdev, hpriv->saved_cap = cap = readl(mmio + HOST_CAP); hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); + /* CAP2 register is only defined for AHCI 1.2 and later */ + vers = readl(mmio + HOST_VERSION); + if ((vers >> 16) > 1 || + ((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200)) + hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2); + else + hpriv->saved_cap2 = cap2 = 0; + /* some chips have errata preventing 64bit use */ if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { dev_printk(KERN_INFO, &pdev->dev, @@ -869,6 +909,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, /* record values to use during operation */ hpriv->cap = cap; + hpriv->cap2 = cap2; hpriv->port_map = port_map; } @@ -887,6 +928,8 @@ static void ahci_restore_initial_config(struct ata_host *host) void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; writel(hpriv->saved_cap, mmio + HOST_CAP); + if (hpriv->saved_cap2) + writel(hpriv->saved_cap2, mmio + HOST_CAP2); writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ } @@ -2534,13 +2577,14 @@ static void ahci_print_info(struct ata_host *host) struct ahci_host_priv *hpriv = host->private_data; struct pci_dev *pdev = to_pci_dev(host->dev); void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - u32 vers, cap, impl, speed; + u32 vers, cap, cap2, impl, speed; const char *speed_s; u16 cc; const char *scc_s; vers = readl(mmio + HOST_VERSION); cap = hpriv->cap; + cap2 = hpriv->cap2; impl = hpriv->port_map; speed = (cap >> 20) & 0xf; @@ -2583,25 +2627,29 @@ static void ahci_print_info(struct ata_host *host) "flags: " "%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s" - "%s\n" + "%s%s%s%s%s%s\n" , - cap & (1 << 31) ? "64bit " : "", - cap & (1 << 30) ? "ncq " : "", - cap & (1 << 29) ? "sntf " : "", - cap & (1 << 28) ? "ilck " : "", - cap & (1 << 27) ? "stag " : "", - cap & (1 << 26) ? "pm " : "", - cap & (1 << 25) ? "led " : "", - - cap & (1 << 24) ? "clo " : "", - cap & (1 << 19) ? "nz " : "", - cap & (1 << 18) ? "only " : "", - cap & (1 << 17) ? "pmp " : "", - cap & (1 << 15) ? "pio " : "", - cap & (1 << 14) ? "slum " : "", - cap & (1 << 13) ? "part " : "", - cap & (1 << 6) ? "ems ": "" + cap & HOST_CAP_64 ? "64bit " : "", + cap & HOST_CAP_NCQ ? "ncq " : "", + cap & HOST_CAP_SNTF ? "sntf " : "", + cap & HOST_CAP_MPS ? "ilck " : "", + cap & HOST_CAP_SSS ? "stag " : "", + cap & HOST_CAP_ALPM ? "pm " : "", + cap & HOST_CAP_LED ? "led " : "", + cap & HOST_CAP_CLO ? "clo " : "", + cap & HOST_CAP_ONLY ? "only " : "", + cap & HOST_CAP_PMP ? "pmp " : "", + cap & HOST_CAP_FBS ? "fbs " : "", + cap & HOST_CAP_PIO_MULTI ? "pio " : "", + cap & HOST_CAP_SSC ? "slum " : "", + cap & HOST_CAP_PART ? "part " : "", + cap & HOST_CAP_CCC ? "ccc " : "", + cap & HOST_CAP_EMS ? "ems " : "", + cap & HOST_CAP_SXS ? "sxs " : "", + cap2 & HOST_CAP2_APST ? "apst " : "", + cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "", + cap2 & HOST_CAP2_BOH ? "boh " : "" ); } @@ -2650,17 +2698,15 @@ static void ahci_p5wdh_workaround(struct ata_host *host) } } -/* - * SB600 ahci controller on certain boards can't do 64bit DMA with - * older BIOS. - */ -static bool ahci_sb600_32bit_only(struct pci_dev *pdev) +/* only some SB600 ahci controllers can do 64bit DMA */ +static bool ahci_sb600_enable_64bit(struct pci_dev *pdev) { static const struct dmi_system_id sysids[] = { /* * 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. + * Enable 64bit DMA on 1501 and anything newer. + * * Please read bko#9412 for more info. */ { @@ -2673,46 +2719,57 @@ static bool ahci_sb600_32bit_only(struct pci_dev *pdev) .driver_data = "20071026", /* yyyymmdd */ }, /* - * It's yet unknown whether more recent BIOS fixes the - * problem. Blacklist the whole board for the time - * being. Please read the following thread for more - * info. + * All BIOS versions for the MSI K9A2 Platinum (MS-7376) + * support 64bit DMA. * - * http://thread.gmane.org/gmane.linux.ide/42326 + * BIOS versions earlier than 1.5 had the Manufacturer DMI + * fields as "MICRO-STAR INTERANTIONAL CO.,LTD". + * This spelling mistake was fixed in BIOS version 1.5, so + * 1.5 and later have the Manufacturer as + * "MICRO-STAR INTERNATIONAL CO.,LTD". + * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER". + * + * BIOS versions earlier than 1.9 had a Board Product Name + * DMI field of "MS-7376". This was changed to be + * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still + * match on DMI_BOARD_NAME of "MS-7376". */ { - .ident = "Gigabyte GA-MA69VM-S2", + .ident = "MSI K9A2 Platinum", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, - "Gigabyte Technology Co., Ltd."), - DMI_MATCH(DMI_BOARD_NAME, "GA-MA69VM-S2"), + "MICRO-STAR INTER"), + DMI_MATCH(DMI_BOARD_NAME, "MS-7376"), }, }, { } }; const struct dmi_system_id *match; + int year, month, date; + char buf[9]; match = dmi_first_match(sysids); if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) || !match) return false; - if (match->driver_data) { - int year, month, date; - char buf[9]; - - dmi_get_date(DMI_BIOS_DATE, &year, &month, &date); - snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date); + if (!match->driver_data) + goto enable_64bit; - if (strcmp(buf, match->driver_data) >= 0) - return false; + dmi_get_date(DMI_BIOS_DATE, &year, &month, &date); + snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date); + if (strcmp(buf, match->driver_data) >= 0) + goto enable_64bit; + else { dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, " "forcing 32bit DMA, update BIOS\n", match->ident); - } else - dev_printk(KERN_WARNING, &pdev->dev, "%s: this board can't " - "do 64bit DMA, forcing 32bit\n", match->ident); + return false; + } +enable_64bit: + dev_printk(KERN_WARNING, &pdev->dev, "%s: enabling 64bit DMA\n", + match->ident); return true; } @@ -2858,6 +2915,55 @@ static bool ahci_broken_online(struct pci_dev *pdev) return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); } +#ifdef CONFIG_ATA_ACPI +static void ahci_gtf_filter_workaround(struct ata_host *host) +{ + static const struct dmi_system_id sysids[] = { + /* + * Aspire 3810T issues a bunch of SATA enable commands + * via _GTF including an invalid one and one which is + * rejected by the device. Among the successful ones + * is FPDMA non-zero offset enable which when enabled + * only on the drive side leads to NCQ command + * failures. Filter it out. + */ + { + .ident = "Aspire 3810T", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"), + }, + .driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET, + }, + { } + }; + const struct dmi_system_id *dmi = dmi_first_match(sysids); + unsigned int filter; + int i; + + if (!dmi) + return; + + filter = (unsigned long)dmi->driver_data; + dev_printk(KERN_INFO, host->dev, + "applying extra ACPI _GTF filter 0x%x for %s\n", + filter, dmi->ident); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + struct ata_link *link; + struct ata_device *dev; + + ata_for_each_link(link, ap, EDGE) + ata_for_each_dev(dev, link, ALL) + dev->gtf_filter |= filter; + } +} +#else +static inline void ahci_gtf_filter_workaround(struct ata_host *host) +{} +#endif + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; @@ -2926,9 +3032,9 @@ 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 sb600 32bit only quirk */ - if (ahci_sb600_32bit_only(pdev)) - hpriv->flags |= AHCI_HFLAG_32BIT_ONLY; + /* only some SB600s can do 64bit DMA */ + if (ahci_sb600_enable_64bit(pdev)) + hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY; if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) pci_intx(pdev, 1); @@ -3023,6 +3129,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* apply workaround for ASUS P5W DH Deluxe mainboard */ ahci_p5wdh_workaround(host); + /* apply gtf filter quirk */ + ahci_gtf_filter_workaround(host); + /* initialize adapter */ rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); if (rc) |