Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Aug 2009 19:19:15 GMT
From:      Alexander Motin <mav@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 167744 for review
Message-ID:  <200908241919.n7OJJFH6010752@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=167744

Change 167744 by mav@mav_mavbook on 2009/08/24 19:18:43

	Implement PM levels 4 and 5. Alike to 2 and 3, but implemented on
	driver level. Performance degradation is smaller and not so controller
	dependent.

Affected files ...

.. //depot/projects/scottl-camlock/src/share/man/man4/ahci.4#5 edit
.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#51 edit
.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#18 edit

Differences ...

==== //depot/projects/scottl-camlock/src/share/man/man4/ahci.4#5 (text+ko) ====

@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD: src/share/man/man4/ahci.4,v 1.2 2009/07/25 18:19:31 mav Exp $
 .\"
-.Dd June 26, 2009
+.Dd August 24, 2009
 .Dt AHCI 4
 .Os
 .Sh NAME
@@ -74,7 +74,15 @@
 host initiates PARTIAL PM state transition every time port becomes idle;
 .It 3
 host initiates SLUMBER PM state transition every time port becomes idle.
+.It 4
+driver initiates PARTIAL PM state transition 1ms after port becomes idle;
+.It 5
+driver initiates SLUMBER PM state transition 125ms after port becomes idle.
 .El
+Some controllers, such as ICH8, do not implement modes 2 and 3 with NCQ used.
+Because of artificial entering latency, performance degradation in modes
+4 and 5 is much smaller then in modes 2 and 3.
+.Pp
 Note that interface Power Management is not compatible with
 device presence detection.
 You will have to reset bus manually on device hot-plug.

==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#51 (text+ko) ====

@@ -63,6 +63,7 @@
 static int ahci_resume(device_t dev);
 static int ahci_ch_suspend(device_t dev);
 static int ahci_ch_resume(device_t dev);
+static void ahci_ch_pm(void *arg);
 static void ahci_ch_intr_locked(void *data);
 static void ahci_ch_intr(void *data);
 static int ahci_ctlr_reset(device_t dev);
@@ -531,8 +532,11 @@
 	ch->caps = ATA_INL(ctlr->r_mem, AHCI_CAP);
 	ch->caps2 = ATA_INL(ctlr->r_mem, AHCI_CAP2);
 	ch->numslots = ((ch->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1,
+	mtx_init(&ch->mtx, "AHCI channel lock", NULL, MTX_DEF);
 	resource_int_value(device_get_name(dev),
 	    device_get_unit(dev), "pm_level", &ch->pm_level);
+	if (ch->pm_level > 3)
+		callout_init_mtx(&ch->pm_timer, &ch->mtx, 0);
 	/* Limit speed for my onboard JMicron external port.
 	 * It is not eSATA really. */
 	if (pci_get_devid(ctlr->dev) == 0x2363197b &&
@@ -542,7 +546,6 @@
 		ch->sata_rev = 1;
 	resource_int_value(device_get_name(dev),
 	    device_get_unit(dev), "sata_rev", &ch->sata_rev);
-	mtx_init(&ch->mtx, "AHCI channel lock", NULL, MTX_DEF);
 	rid = ch->unit;
 	if (!(ch->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
 	    &rid, RF_ACTIVE)))
@@ -590,6 +593,11 @@
 		error = ENXIO;
 		goto err3;
 	}
+	if (ch->pm_level > 3) {
+		callout_reset(&ch->pm_timer,
+		    (ch->pm_level == 4) ? hz / 1000 : hz / 8,
+		    ahci_ch_pm, dev);
+	}
 	mtx_unlock(&ch->mtx);
 	return (0);
 
@@ -616,6 +624,8 @@
 	cam_sim_free(ch->sim, /*free_devq*/TRUE);
 	mtx_unlock(&ch->mtx);
 
+	if (ch->pm_level > 3)
+		callout_drain(&ch->pm_timer);
 	bus_teardown_intr(dev, ch->r_irq, ch->ih);
 	bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
 
@@ -667,7 +677,7 @@
 	/* Activate the channel and power/spin up device */
 	ATA_OUTL(ch->r_mem, AHCI_P_CMD,
 	     (AHCI_P_CMD_ACTIVE | AHCI_P_CMD_POD | AHCI_P_CMD_SUD |
-	     ((ch->pm_level > 1) ? AHCI_P_CMD_ALPE : 0) |
+	     ((ch->pm_level == 2 || ch->pm_level == 3) ? AHCI_P_CMD_ALPE : 0) |
 	     ((ch->pm_level > 2) ? AHCI_P_CMD_ASP : 0 )));
 	ahci_start_fr(dev);
 	ahci_start(dev);
@@ -890,6 +900,23 @@
 }
 
 static void
+ahci_ch_pm(void *arg)
+{
+	device_t dev = (device_t)arg;
+	struct ahci_channel *ch = device_get_softc(dev);
+	uint32_t work;
+
+	if (ch->numrslots != 0)
+		return;
+	work = ATA_INL(ch->r_mem, AHCI_P_CMD);
+	if (ch->pm_level == 4)
+		work |= AHCI_P_CMD_PARTIAL;
+	else
+		work |= AHCI_P_CMD_SLUMBER;
+	ATA_OUTL(ch->r_mem, AHCI_P_CMD, work);
+}
+
+static void
 ahci_ch_intr(void *data)
 {
 	device_t dev = (device_t)data;
@@ -1027,6 +1054,9 @@
 	/* Occupy chosen slot. */
 	slot = &ch->slot[tag];
 	slot->ccb = ccb;
+	/* Stop PM timer. */
+	if (ch->numrslots == 0 && ch->pm_level > 3)
+		callout_stop(&ch->pm_timer);
 	/* Update channel stats. */
 	ch->numrslots++;
 	if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
@@ -1336,6 +1366,11 @@
 		ahci_begin_transaction(dev, fccb);
 		xpt_release_simq(ch->sim, TRUE);
 	}
+	/* Start PM timer. */
+	if (ch->numrslots == 0 && ch->pm_level > 3) {
+		callout_schedule(&ch->pm_timer,
+		    (ch->pm_level == 4) ? hz / 1000 : hz / 8);
+	}
 }
 
 static void

==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#18 (text+ko) ====

@@ -359,6 +359,7 @@
 	int			lastslot;	/* Last used slot */
 	int			taggedtarget;	/* Last tagged target */
 	union ccb		*frozen;	/* Frozen command */
+	struct callout		pm_timer;	/* Power management events */
 };
 
 /* structure describing a AHCI controller */



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