Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f80ae7e4 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

ahci: filter FPDMA non-zero offset enable for Aspire 3810T

Curiously, Aspire 3810T issues many SATA feature enable commands via
_GTF, of which one is invalid and another is not supported by the
drive.  In the process, it also enables FPDMA non-zero offset.
However, the feature also needs to be supported and enabled from the
controller and it's wrong to enable it from _GTF unless the controller
can do it by default.

Currently, this ends up enabling FPDMA non-zero offset only on the
drive side leading to NCQ command failures and eventual disabling of
NCQ.  This patch makes libata filter out FPDMA non-zero offset enable
for the machine.

This was reported by Marcus Meissner in bnc#522790.

  https://bugzilla.novell.com/show_bug.cgi?id=522790



Reported-by: default avatarMarcus Meissner <meissner@novell.com>

Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 110f66d2
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -2884,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;
@@ -3049,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)