2006-09-27 02:56:41

by Jeff Garzik

[permalink] [raw]
Subject: [PATCH][RFT] libata AHCI reset speed-up, improvements


This patch, diff'd against 2.6.18-git5 (or later), attempts the
following improvements:

* Speed up reset, by polling rather than unconditionally sleeping
for one seconds.
* Save the Ports-Implemented register across controller resets.
* Verify that AHCI mode was truly enabled.

I'm quite interested in hearing people's test feedback on this patch.
On my own ICH7 machine, it introduces a "softreset failed" error, but
EH recovers nicely and nonetheless configures everything successfully.
Probably just a slow ATAPI device, but I may have exposed a latent
problem in the driver that was hidden until now by the ssleep(1).

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 1aabc81..1def9c9 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -40,6 +40,7 @@ #include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
+#include <linux/jiffies.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
@@ -593,11 +594,13 @@ static int ahci_deinit_port(void __iomem

static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
{
- u32 cap_save, tmp;
+ u32 cap_save, impl_save, tmp;
+ unsigned long end_time;

cap_save = readl(mmio + HOST_CAP);
cap_save &= ( (1<<28) | (1<<17) );
cap_save |= (1 << 27);
+ impl_save = readl(mmio + HOST_PORTS_IMPL);

/* global controller reset */
tmp = readl(mmio + HOST_CTL);
@@ -609,19 +612,36 @@ static int ahci_reset_controller(void __
/* reset must complete within 1 second, or
* the hardware should be considered fried.
*/
- ssleep(1);
+ end_time = jiffies + HZ;
+ while (1) {
+ msleep(100);
+
+ tmp = readl(mmio + HOST_CTL);
+ if (!(tmp & HOST_RESET))
+ break;
+ if (time_after(jiffies, end_time))
+ break;
+
+ }

- tmp = readl(mmio + HOST_CTL);
if (tmp & HOST_RESET) {
dev_printk(KERN_ERR, &pdev->dev,
"controller reset failed (0x%x)\n", tmp);
return -EIO;
}

+ /* turn on AHCI mode */
writel(HOST_AHCI_EN, mmio + HOST_CTL);
(void) readl(mmio + HOST_CTL); /* flush */
+
+ /*
+ * these write-once registers are normally cleared
+ * on reset. Restore BIOS values... which we HOPE
+ * were present before reset.
+ */
+
writel(cap_save, mmio + HOST_CAP);
- writel(0xf, mmio + HOST_PORTS_IMPL);
+ writel(impl_save, mmio + HOST_PORTS_IMPL);
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */

if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
@@ -633,6 +653,19 @@ static int ahci_reset_controller(void __
pci_write_config_word(pdev, 0x92, tmp16);
}

+ /*
+ * if AHCI failed to enable, AHCI function may not
+ * be present in the chipset. This is true of certain
+ * ICHx chipsets, which export the SATA phy registers
+ * via the AHCI memory space, but don't support full AHCI.
+ */
+ tmp = readl(mmio + HOST_CTL);
+ if (!(tmp & HOST_AHCI_EN)) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "AHCI enable failed (0x%x)\n", tmp);
+ return -ENODEV;
+ }
+
return 0;
}


2006-10-04 09:13:14

by Michael S. Tsirkin

[permalink] [raw]
Subject: Re: [PATCH][RFT] libata AHCI reset speed-up, improvements

Quoting Jeff Garzik <[email protected]>:
> Subject: [PATCH][RFT] libata AHCI reset speed-up, improvements
>
>
> This patch, diff'd against 2.6.18-git5 (or later), attempts the
> following improvements:
>
> * Speed up reset, by polling rather than unconditionally sleeping
> for one seconds.
> * Save the Ports-Implemented register across controller resets.
> * Verify that AHCI mode was truly enabled.
>
> I'm quite interested in hearing people's test feedback on this patch.
> On my own ICH7 machine, it introduces a "softreset failed" error, but
> EH recovers nicely and nonetheless configures everything successfully.
> Probably just a slow ATAPI device, but I may have exposed a latent
> problem in the driver that was hidden until now by the ssleep(1).

Hi Jeff!
I tested this patch on my T60 (Intel ICH7)
against git 78b656b8bf933101b42409b4492734b23427bfc3
with the same result: during boot, I get
scsi0: ahci
ata1: port is slow to respond, pls be patient
ata1: port failed to respond (30 sec)
ata1: soft reset failed (device not ready)
ata1: soft reset failed retrying in 5 secs
etc

after a while everything recovers and seems to work OK
afterwards, but still this seems to add about a minute or so
to the boot time.

I'm not sure how to test whether I get the speedup that you
mention.

Hope this report helps.


--
MST