|
@@ -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,
|
|
@@ -732,6 +753,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 +802,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 +815,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 +908,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 +927,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 +2576,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 +2626,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 +2697,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.
|
|
|
*/
|
|
|
{
|
|
@@ -2672,48 +2717,29 @@ 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.
|
|
|
- *
|
|
|
- * http://thread.gmane.org/gmane.linux.ide/42326
|
|
|
- */
|
|
|
- {
|
|
|
- .ident = "Gigabyte GA-MA69VM-S2",
|
|
|
- .matches = {
|
|
|
- DMI_MATCH(DMI_BOARD_VENDOR,
|
|
|
- "Gigabyte Technology Co., Ltd."),
|
|
|
- DMI_MATCH(DMI_BOARD_NAME, "GA-MA69VM-S2"),
|
|
|
- },
|
|
|
- },
|
|
|
{ }
|
|
|
};
|
|
|
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 (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) {
|
|
|
+ dev_printk(KERN_WARNING, &pdev->dev, "%s: enabling 64bit DMA\n",
|
|
|
+ match->ident);
|
|
|
+ return true;
|
|
|
+ } 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 true;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
|
|
@@ -2858,6 +2884,50 @@ static bool ahci_broken_online(struct pci_dev *pdev)
|
|
|
return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
|
|
|
}
|
|
|
|
|
|
+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;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
{
|
|
|
static int printed_version;
|
|
@@ -2926,9 +2996,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 +3093,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)
|