PERFORCE change 167744 for review
Alexander Motin
mav at FreeBSD.org
Mon Aug 24 19:19:16 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=167744
Change 167744 by mav at 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 */
More information about the p4-projects
mailing list