ioat(4): Add support for 'fence' bit with DMA_FENCE flag

Some classes of IOAT hardware prefetch reads.  DMA operations that
depend on the result of prior DMA operations must use the DMA_FENCE flag
to prevent stale reads.

(E.g., I've hit this personally on Broadwell-EP.  The Broadwell-DE has a
different IOAT unit that is documented to not pipeline DMA operations.)

Sponsored by:	EMC / Isilon Storage Division
This commit is contained in:
Conrad Meyer 2016-01-15 01:34:43 +00:00
parent b2ec7c304e
commit 6ca07079af
3 changed files with 22 additions and 3 deletions

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd January 7, 2016
.Dd January 14, 2016
.Dt IOAT 4
.Os
.Sh NAME
@ -134,7 +134,7 @@ Null operations do nothing, but may be used to test the interrupt and callback
mechanism.
.Pp
All operations can optionally trigger an interrupt at completion with the
.Ar DMA_EN_INT
.Ar DMA_INT_EN
flag.
For example, a user might submit multiple operations to the same channel and
only enable an interrupt and callback for the last operation.
@ -160,6 +160,17 @@ flag.
.Ar DMA_NO_WAIT
may return NULL.)
.Pp
Operations that depend on the result of prior operations should use
.Ar DMA_FENCE .
For example, such a scenario can happen when two related DMA operations are
queued.
First, a DMA copy to one location (A), followed directly by a DMA copy
from A to B.
In this scenario, some classes of I/OAT hardware may prefetch A for the second
operation before it is written by the first operation.
To avoid reading a stale value in sequences of dependent operations, use
.Ar DMA_FENCE .
.Pp
All operations, as well as
.Fn ioat_get_dmaengine ,
can return NULL in special circumstances.

View File

@ -852,6 +852,8 @@ ioat_op_generic(struct ioat_softc *ioat, uint8_t op,
if ((flags & DMA_INT_EN) != 0)
hw_desc->u.control_generic.int_enable = 1;
if ((flags & DMA_FENCE) != 0)
hw_desc->u.control_generic.fence = 1;
hw_desc->size = size;
hw_desc->src_addr = src;

View File

@ -46,7 +46,13 @@ __FBSDID("$FreeBSD$");
* descriptor without blocking.
*/
#define DMA_NO_WAIT 0x2
#define DMA_ALL_FLAGS (DMA_INT_EN | DMA_NO_WAIT)
/*
* Disallow prefetching the source of the following operation. Ordinarily, DMA
* operations can be pipelined on some hardware. E.g., operation 2's source
* may be prefetched before operation 1 completes.
*/
#define DMA_FENCE 0x4
#define DMA_ALL_FLAGS (DMA_INT_EN | DMA_NO_WAIT | DMA_FENCE)
/*
* Hardware revision number. Different hardware revisions support different