From: Tejun Heo <htejun@gmail.com>
To: Jeff Garzik <jeff@garzik.org>,
IDE/ATA development list <linux-ide@vger.kernel.org>,
Alan Cox <alan@lxorguk.ukuu.org.uk>
Subject: [PATCH 3/3] pata_amd: fix and improve cable detection
Date: Sat, 03 Nov 2007 00:22:24 +0900 [thread overview]
Message-ID: <472B40B0.6010702@gmail.com> (raw)
In-Reply-To: <472B4078.90009@gmail.com>
Cable detection on Nvidia PATA hosts is pathetic. The current
nv_cable_detect() assumes that the native cable detection only
mistakes 80c as 40c but this isn't true. On ASUS A8N-E, cable
register almost always says 80c is attached and it also manages to
trick the drive that the cable is 80c.
Also, BIOS checking, and before the get_acpi_cbl() update ACPI
checking too, in the current implementation were useless because they
read the setting _after_ reset is complete which forces the host into
PIO0, so they never triggered.
Reimplement nv_cable_detect() such that...
* BIOS setting is cached during controller initialization and restored
on driver detach.
* BIOS and ACPI cable results are considered more important. Native
cable bits are used iff both BIOS and ACPI results are PATA_UNK. If
BIOS or ACPI indicates 80c, it's 80c. If none indicates 80c, it's
40c.
This change makes cable detection work correctly all the time on ASUS
A8N-E and should also work well on other NV PATA configurations.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/pata_amd.c | 112 +++++++++++++++++++++++++++++++++++++++----------
1 file changed, 90 insertions(+), 22 deletions(-)
Index: work/drivers/ata/pata_amd.c
===================================================================
--- work.orig/drivers/ata/pata_amd.c
+++ work/drivers/ata/pata_amd.c
@@ -255,26 +255,69 @@ static int nv_cable_detect(struct ata_po
{
static const u8 bitmask[2] = {0x03, 0x0C};
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *dev;
+ char acpi_str[32] = "";
+ int native_cbl, bios_cbl, acpi_cbl, verdict;
+ u32 saved_udma, udma;
u8 ata66;
- u16 udma;
- int cbl;
+ /* native method, this is usually broken */
pci_read_config_byte(pdev, 0x52, &ata66);
if (ata66 & bitmask[ap->port_no])
- cbl = ATA_CBL_PATA80;
+ native_cbl = ATA_CBL_PATA80;
else
- cbl = ATA_CBL_PATA40;
+ native_cbl = ATA_CBL_PATA40;
- /* We now have to double check because the Nvidia boxes BIOS
- doesn't always set the cable bits but does set mode bits */
- pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
- if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
- cbl = ATA_CBL_PATA80;
- /* And a triple check across suspend/resume with ACPI around */
- if ((ap->pflags & ATA_PFLAG_INIT_GTM_VALID) &&
- ata_acpi_cbl(ap, &ap->acpi_init_gtm) == ATA_CBL_PATA80)
- cbl = ATA_CBL_PATA80;
- return cbl;
+ /* peek BIOS configuration */
+ bios_cbl = ATA_CBL_PATA_UNK;
+
+ saved_udma = udma = (unsigned long)ap->host->private_data;
+ if (ap->port_no == 0)
+ udma >>= 16;
+
+ ata_link_for_each_dev(dev, &ap->link) {
+ u32 tmp = udma;
+
+ if (dev->devno == 0)
+ tmp >>= 8;
+
+ if (!ata_dev_enabled(dev) || (tmp & 0xC0) != 0xC0)
+ continue;
+
+ if (tmp & 0x4)
+ bios_cbl = ATA_CBL_PATA80;
+ else
+ bios_cbl = ATA_CBL_PATA40;
+ }
+
+ /* and ACPI configuration */
+ acpi_cbl = ATA_CBL_PATA_UNK;
+ if (ap->pflags & ATA_PFLAG_INIT_GTM_VALID)
+ acpi_cbl = ata_acpi_cbl(ap, &ap->acpi_init_gtm);
+
+ /* Three values collected. Native value is usually
+ * untrustworthy. Consider it iff both BIOS and ACPI values
+ * are unknown; otherwise, choose higher of the two.
+ */
+ if (bios_cbl == ATA_CBL_PATA_UNK && acpi_cbl == ATA_CBL_PATA_UNK)
+ verdict = native_cbl;
+ else if (bios_cbl == ATA_CBL_PATA80 || acpi_cbl == ATA_CBL_PATA80)
+ verdict = ATA_CBL_PATA80;
+ else
+ verdict = ATA_CBL_PATA40;
+
+ if (ap->pflags & ATA_PFLAG_INIT_GTM_VALID)
+ snprintf(acpi_str, sizeof(acpi_str), " (%u:%u:0x%x)",
+ ap->acpi_init_gtm.drive[0].dma,
+ ap->acpi_init_gtm.drive[1].dma,
+ ap->acpi_init_gtm.flags);
+
+ ata_port_printk(ap, KERN_DEBUG, "nv_cable_detect: native=%d (0x%x) "
+ "BIOS=%d (0x%x) ACPI=%d%s verdict=%d\n",
+ native_cbl, ata66, bios_cbl, saved_udma, acpi_cbl,
+ acpi_str, verdict);
+
+ return verdict;
}
/**
@@ -314,6 +357,14 @@ static void nv133_set_dmamode(struct ata
timing_setup(ap, adev, 0x50, adev->dma_mode, 4);
}
+static void nv_host_stop(struct ata_host *host)
+{
+ u32 udma = (unsigned long)host->private_data;
+
+ /* restore PCI config register 0x60 */
+ pci_write_config_dword(to_pci_dev(host->dev), 0x60, udma);
+}
+
static struct scsi_host_template amd_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -495,6 +546,7 @@ static struct ata_port_operations nv100_
.irq_on = ata_irq_on,
.port_start = ata_sff_port_start,
+ .host_stop = nv_host_stop,
};
static struct ata_port_operations nv133_port_ops = {
@@ -528,6 +580,7 @@ static struct ata_port_operations nv133_
.irq_on = ata_irq_on,
.port_start = ata_sff_port_start,
+ .host_stop = nv_host_stop,
};
static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -614,7 +667,8 @@ static int amd_init_one(struct pci_dev *
.port_ops = &amd100_port_ops
}
};
- const struct ata_port_info *ppi[] = { NULL, NULL };
+ struct ata_port_info pi;
+ const struct ata_port_info *ppi[] = { &pi, NULL };
static int printed_version;
int type = id->driver_data;
u8 fifo;
@@ -628,6 +682,19 @@ static int amd_init_one(struct pci_dev *
if (type == 1 && pdev->revision > 0x7)
type = 2;
+ /* Serenade ? */
+ if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+ pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+ type = 6; /* UDMA 100 only */
+
+ /*
+ * Okay, type is determined now. Apply type-specific workarounds.
+ */
+ pi = info[type];
+
+ if (type < 3)
+ ata_pci_clear_simplex(pdev);
+
/* Check for AMD7411 */
if (type == 3)
/* FIFO is broken */
@@ -635,16 +702,17 @@ static int amd_init_one(struct pci_dev *
else
pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
- /* Serenade ? */
- if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
- pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
- type = 6; /* UDMA 100 only */
+ /* Cable detection on Nvidia chips doesn't work too well,
+ * cache BIOS programmed UDMA mode.
+ */
+ if (type == 7 || type == 8) {
+ u32 udma;
- if (type < 3)
- ata_pci_clear_simplex(pdev);
+ pci_read_config_dword(pdev, 0x60, &udma);
+ pi.private_data = (void *)(unsigned long)udma;
+ }
/* And fire it up */
- ppi[0] = &info[type];
return ata_pci_init_one(pdev, ppi);
}
next prev parent reply other threads:[~2007-11-02 15:22 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-02 15:20 [PATCH 1/3] libata: implement dev->acpi_init_gtm Tejun Heo
2007-11-02 15:21 ` [PATCH 2/3] libata: extend ata_acpi_cbl_80wire() and fix cable detection in pata_via and pata_amd Tejun Heo
2007-11-02 15:22 ` Tejun Heo [this message]
2007-11-02 15:44 ` [PATCH 3/3] pata_amd: fix and improve cable detection Alan Cox
2007-11-02 22:22 ` Tejun Heo
2007-11-03 0:10 ` Alan Cox
2007-11-03 0:35 ` Tejun Heo
2007-11-03 0:42 ` Tejun Heo
2007-11-02 15:42 ` [PATCH 2/3] libata: extend ata_acpi_cbl_80wire() and fix cable detection in pata_via and pata_amd Alan Cox
2007-11-02 22:18 ` Tejun Heo
2007-11-02 23:45 ` Alan Cox
2007-11-03 0:46 ` Tejun Heo
2007-11-03 1:12 ` Alan Cox
2007-11-03 1:16 ` Tejun Heo
2007-11-03 1:23 ` Alan Cox
2007-11-03 7:03 ` Tejun Heo
2007-11-03 0:57 ` Bartlomiej Zolnierkiewicz
2007-11-03 1:12 ` Bartlomiej Zolnierkiewicz
2007-11-02 15:36 ` [PATCH 1/3] libata: implement dev->acpi_init_gtm Jeff Garzik
2007-11-02 22:12 ` Tejun Heo
2007-11-03 7:10 ` Tejun Heo
2007-11-03 12:33 ` Jeff Garzik
2007-11-02 15:44 ` Alan Cox
2007-11-02 22:08 ` Tejun Heo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=472B40B0.6010702@gmail.com \
--to=htejun@gmail.com \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=jeff@garzik.org \
--cc=linux-ide@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).