Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 14 Feb 2009 23:02:59 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r188621 - head/sys/dev/ata/chipsets
Message-ID:  <200902142302.n1EN2xp0032837@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Feb 14 23:02:59 2009
New Revision: 188621
URL: http://svn.freebsd.org/changeset/base/188621

Log:
  Tunes to AHCI reset sequences:
  - specification claims that 1 second is just a maximum controller reset time;
  implement controller reset properly to save almost 1 second of boot, and
  about half second of resume time;
  - enable channel interrupts only after channel status reset to fix duplicate
  device creation on resume due to unwanted device connection event;
  - as described in specification, wait for disk ready status after channel
  power-up; it is not so important when disk already touched by BIOS, but
  solves device not ready problems on resume and probably some other cases.
  - uncomment channel stop/start on soft-reset as it is declared mandatory by
  specification; it was commented due to some random drive detection problems
  on VIA and JMicron controllers, but I hope it is fixed by previous point.

Modified:
  head/sys/dev/ata/chipsets/ata-ahci.c

Modified: head/sys/dev/ata/chipsets/ata-ahci.c
==============================================================================
--- head/sys/dev/ata/chipsets/ata-ahci.c	Sat Feb 14 23:02:21 2009	(r188620)
+++ head/sys/dev/ata/chipsets/ata-ahci.c	Sat Feb 14 23:02:59 2009	(r188621)
@@ -153,14 +153,19 @@ static int
 ata_ahci_ctlr_reset(device_t dev)
 {
     struct ata_pci_controller *ctlr = device_get_softc(dev);
+    int timeout;
 
     /* enable AHCI mode */
     ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
 
     /* reset AHCI controller */
-    ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_HR);
-    DELAY(1000000);
-    if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE|ATA_AHCI_GHC_HR);
+    for (timeout = 1000; timeout > 0; timeout--) {
+	    DELAY(1000);
+	    if ((ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) == 0)
+		    break;
+    }
+    if (timeout == 0) {
 	device_printf(dev, "AHCI controller reset failure\n");
 	return ENXIO;
     }
@@ -517,7 +522,7 @@ ata_ahci_pm_write(device_t dev, int port
 }
 
 static void
-ata_ahci_restart(device_t dev)
+ata_ahci_stop(device_t dev)
 {
     struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
     struct ata_channel *ch = device_get_softc(dev);
@@ -540,6 +545,16 @@ ata_ahci_restart(device_t dev)
 	}
     }
     while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
+}
+
+static void
+ata_ahci_clo(device_t dev)
+{
+    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+    struct ata_channel *ch = device_get_softc(dev);
+    u_int32_t cmd;
+    int offset = ch->unit << 7;
+    int timeout;
 
     /* issue Command List Override if supported */ 
     if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) {
@@ -556,6 +571,15 @@ ata_ahci_restart(device_t dev)
         }
 	while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO);
     }
+}
+
+static void
+ata_ahci_start(device_t dev)
+{
+    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+    struct ata_channel *ch = device_get_softc(dev);
+    u_int32_t cmd;
+    int offset = ch->unit << 7;
 
     /* clear SATA error register */
     ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
@@ -571,19 +595,39 @@ ata_ahci_restart(device_t dev)
 	     (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0));
 }
 
+static void
+ata_ahci_wait_ready(device_t dev)
+{
+    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+    struct ata_channel *ch = device_get_softc(dev);
+    int offset = ch->unit << 7;
+    int timeout = 0;
+
+    while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) &
+	(ATA_S_BUSY | ATA_S_DRQ)) {
+	    DELAY(1000);
+	    if (timeout++ > 1000) {
+		device_printf(dev, "port is not ready\n");
+		break;
+	    }
+    } 
+    if (bootverbose)
+	device_printf(dev, "ready wait time=%dms\n", timeout);
+}
+
 static u_int32_t
 ata_ahci_softreset(device_t dev, int port)
 {
     struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
     struct ata_channel *ch = device_get_softc(dev);
     int offset = ch->unit << 7;
-    int timeout = 0;
-#ifdef AHCI_PM
     struct ata_ahci_cmd_tab *ctp =
 	(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
 
-    /* kick controller into sane state if needed */
-    ata_ahci_restart(dev);
+    /* kick controller into sane state */
+    ata_ahci_stop(dev);
+    ata_ahci_clo(dev);
+    ata_ahci_start(dev);
 
     /* pull reset active */
     bzero(ctp->cfis, 64);
@@ -607,18 +651,7 @@ ata_ahci_softreset(device_t dev, int por
     if (ata_ahci_issue_cmd(dev, 0, 0))
 	return -1;
 
-    ata_udelay(150000);
-
-#endif
-    do {
-	    DELAY(1000);
-	    if (timeout++ > 1000) {
-		device_printf(dev, "still BUSY after softreset\n");
-		break;
-	    }
-    } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) & ATA_S_BUSY);
-    if (bootverbose)
-	device_printf(dev, "BUSY wait time=%dms\n", timeout);
+    ata_ahci_wait_ready(dev);
 
     return ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
 }
@@ -629,7 +662,7 @@ ata_ahci_reset(device_t dev)
     struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
     struct ata_channel *ch = device_get_softc(dev);
     u_int64_t work;
-    u_int32_t cmd, signature;
+    u_int32_t signature;
     int offset = ch->unit << 7;
 
     if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) {
@@ -646,19 +679,11 @@ ata_ahci_reset(device_t dev)
     ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff); 
     ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32);
 
-    /* enable wanted port interrupts */
-    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
-	     (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
-	      ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
-	      ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP |
-	      ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS |
-	      ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
-
     /* activate the channel and power/spin up device */
     ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
 	     (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD));
 
-    ata_ahci_restart(dev);
+    ata_ahci_stop(dev);
 
     /* enable FIS based switching */
     //ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, 0x00000003);
@@ -668,13 +693,25 @@ ata_ahci_reset(device_t dev)
 	    device_printf(dev, "phy reset found no device\n");
 	ch->devices = 0;
 
-	/* kill off all activity on this channel */
-	cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
-	ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
-		 cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
+	/* enable wanted port interrupts */
+	ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
+	     (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC));
 	return;
     }
 
+    ata_ahci_start(dev);
+
+    /* enable wanted port interrupts */
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
+	     (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
+	      ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
+	      ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP |
+	      ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS |
+	      ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
+
+    /* Wait for initial TFD from device. */
+    ata_ahci_wait_ready(dev);
+
     /* only probe for PortMultiplier if HW has support */
     if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM)
 	signature = ata_ahci_softreset(dev, ATA_PM);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200902142302.n1EN2xp0032837>