svn commit: r292228 - in head: share/man/man4 sys/dev/ioat
Conrad E. Meyer
cem at FreeBSD.org
Mon Dec 14 22:01:54 UTC 2015
Author: cem
Date: Mon Dec 14 22:01:52 2015
New Revision: 292228
URL: https://svnweb.freebsd.org/changeset/base/292228
Log:
ioat(4): Add support for interrupt coalescing
In I/OAT, this is done through the INTRDELAY register. On supported
platforms, this register can coalesce interrupts in a set period to
avoid excessive interrupt load for small descriptor workflows. The
period is configurable anywhere from 1 microsecond to 16.38
milliseconds, in microsecond granularity.
Sponsored by: EMC / Isilon Storage Division
Modified:
head/share/man/man4/ioat.4
head/sys/dev/ioat/ioat.c
head/sys/dev/ioat/ioat.h
head/sys/dev/ioat/ioat_hw.h
head/sys/dev/ioat/ioat_internal.h
Modified: head/share/man/man4/ioat.4
==============================================================================
--- head/share/man/man4/ioat.4 Mon Dec 14 22:00:46 2015 (r292227)
+++ head/share/man/man4/ioat.4 Mon Dec 14 22:01:52 2015 (r292228)
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 9, 2015
+.Dd December 14, 2015
.Dt IOAT 4
.Os
.Sh NAME
@@ -63,6 +63,10 @@ In
.Fn ioat_get_dmaengine "uint32_t channel_index"
.Ft void
.Fn ioat_put_dmaengine "bus_dmaengine_t dmaengine"
+.Ft int
+.Fn ioat_set_interrupt_coalesce "bus_dmaengine_t dmaengine" "uint16_t delay"
+.Ft uint16_t
+.Fn ioat_get_max_coalesce_period "bus_dmaengine_t dmaengine"
.Ft void
.Fn ioat_acquire "bus_dmaengine_t dmaengine"
.Ft void
@@ -129,6 +133,20 @@ flag.
For example, a user might submit multiple operations to the same channel and
only enable an interrupt and callback for the last operation.
.Pp
+The hardware can delay and coalesce interrupts on a given channel for a
+configurable period of time, in microseconds.
+This may be desired to reduce the processing and interrupt overhead per
+descriptor, especially for workflows consisting of many small operations.
+Software can control this on a per-channel basis with the
+.Fn ioat_set_interrupt_coalesce
+API.
+The
+.Fn ioat_get_max_coalesce_period
+API can be used to determine the maximum coalescing period supported by the
+hardware, in microseconds.
+Current platforms support up to a 16.383 millisecond coalescing period.
+Optimal configuration will vary by workflow and desired operation latency.
+.Pp
All operations are safe to use in a non-blocking context with the
.Ar DMA_NO_WAIT
flag.
Modified: head/sys/dev/ioat/ioat.c
==============================================================================
--- head/sys/dev/ioat/ioat.c Mon Dec 14 22:00:46 2015 (r292227)
+++ head/sys/dev/ioat/ioat.c Mon Dec 14 22:01:52 2015 (r292228)
@@ -404,6 +404,11 @@ ioat3_attach(device_t device)
xfercap = ioat_read_xfercap(ioat);
ioat->max_xfer_size = 1 << xfercap;
+ ioat->intrdelay_supported = (ioat_read_2(ioat, IOAT_INTRDELAY_OFFSET) &
+ IOAT_INTRDELAY_SUPPORTED) != 0;
+ if (ioat->intrdelay_supported)
+ ioat->intrdelay_max = IOAT_INTRDELAY_US_MASK;
+
/* TODO: need to check DCA here if we ever do XOR/PQ */
mtx_init(&ioat->submit_lock, "ioat_submit", NULL, MTX_DEF);
@@ -730,6 +735,32 @@ ioat_put_dmaengine(bus_dmaengine_t dmaen
ioat_put(ioat, IOAT_DMAENGINE_REF);
}
+int
+ioat_set_interrupt_coalesce(bus_dmaengine_t dmaengine, uint16_t delay)
+{
+ struct ioat_softc *ioat;
+
+ ioat = to_ioat_softc(dmaengine);
+ if (!ioat->intrdelay_supported)
+ return (ENODEV);
+ if (delay > ioat->intrdelay_max)
+ return (ERANGE);
+
+ ioat_write_2(ioat, IOAT_INTRDELAY_OFFSET, delay);
+ ioat->cached_intrdelay =
+ ioat_read_2(ioat, IOAT_INTRDELAY_OFFSET) & IOAT_INTRDELAY_US_MASK;
+ return (0);
+}
+
+uint16_t
+ioat_get_max_coalesce_period(bus_dmaengine_t dmaengine)
+{
+ struct ioat_softc *ioat;
+
+ ioat = to_ioat_softc(dmaengine);
+ return (ioat->intrdelay_max);
+}
+
void
ioat_acquire(bus_dmaengine_t dmaengine)
{
@@ -1641,6 +1672,11 @@ ioat_setup_sysctl(device_t device)
&ioat->version, 0, "HW version (0xMM form)");
SYSCTL_ADD_UINT(ctx, par, OID_AUTO, "max_xfer_size", CTLFLAG_RD,
&ioat->max_xfer_size, 0, "HW maximum transfer size");
+ SYSCTL_ADD_INT(ctx, par, OID_AUTO, "intrdelay_supported", CTLFLAG_RD,
+ &ioat->intrdelay_supported, 0, "Is INTRDELAY supported");
+ SYSCTL_ADD_U16(ctx, par, OID_AUTO, "intrdelay_max", CTLFLAG_RD,
+ &ioat->intrdelay_max, 0,
+ "Maximum configurable INTRDELAY on this channel (microseconds)");
tmp = SYSCTL_ADD_NODE(ctx, par, OID_AUTO, "state", CTLFLAG_RD, NULL,
"IOAT channel internal state");
@@ -1671,6 +1707,10 @@ ioat_setup_sysctl(device_t device)
CTLTYPE_STRING | CTLFLAG_RD, ioat, 0, sysctl_handle_chansts, "A",
"String of the channel status");
+ SYSCTL_ADD_U16(ctx, state, OID_AUTO, "intrdelay", CTLFLAG_RD,
+ &ioat->cached_intrdelay, 0,
+ "Current INTRDELAY on this channel (cached, microseconds)");
+
tmp = SYSCTL_ADD_NODE(ctx, par, OID_AUTO, "hammer", CTLFLAG_RD, NULL,
"Big hammers (mostly for testing)");
hammer = SYSCTL_CHILDREN(tmp);
Modified: head/sys/dev/ioat/ioat.h
==============================================================================
--- head/sys/dev/ioat/ioat.h Mon Dec 14 22:00:46 2015 (r292227)
+++ head/sys/dev/ioat/ioat.h Mon Dec 14 22:01:52 2015 (r292228)
@@ -61,6 +61,28 @@ bus_dmaengine_t ioat_get_dmaengine(uint3
void ioat_put_dmaengine(bus_dmaengine_t dmaengine);
/*
+ * Set interrupt coalescing on a DMA channel.
+ *
+ * The argument is in microseconds. A zero value disables coalescing. Any
+ * other value delays interrupt generation for N microseconds to provide
+ * opportunity to coalesce multiple operations into a single interrupt.
+ *
+ * Returns an error status, or zero on success.
+ *
+ * - ERANGE if the given value exceeds the delay supported by the hardware.
+ * (All current hardware supports a maximum of 0x3fff microseconds delay.)
+ * - ENODEV if the hardware does not support interrupt coalescing.
+ */
+int ioat_set_interrupt_coalesce(bus_dmaengine_t dmaengine, uint16_t delay);
+
+/*
+ * Return the maximum supported coalescing period, for use in
+ * ioat_set_interrupt_coalesce(). If the hardware does not support coalescing,
+ * returns zero.
+ */
+uint16_t ioat_get_max_coalesce_period(bus_dmaengine_t dmaengine);
+
+/*
* Acquire must be called before issuing an operation to perform. Release is
* called after. Multiple operations can be issued within the context of one
* acquire and release
Modified: head/sys/dev/ioat/ioat_hw.h
==============================================================================
--- head/sys/dev/ioat/ioat_hw.h Mon Dec 14 22:00:46 2015 (r292227)
+++ head/sys/dev/ioat/ioat_hw.h Mon Dec 14 22:01:52 2015 (r292228)
@@ -50,6 +50,10 @@ __FBSDID("$FreeBSD$");
#define IOAT_VER_3_3 0x33
#define IOAT_INTRDELAY_OFFSET 0x0C
+#define IOAT_INTRDELAY_SUPPORTED (1 << 15)
+/* Reserved. (1 << 14) */
+/* [13:0] is the coalesce period, in microseconds. */
+#define IOAT_INTRDELAY_US_MASK ((1 << 14) - 1)
#define IOAT_CS_STATUS_OFFSET 0x0E
Modified: head/sys/dev/ioat/ioat_internal.h
==============================================================================
--- head/sys/dev/ioat/ioat_internal.h Mon Dec 14 22:00:46 2015 (r292227)
+++ head/sys/dev/ioat/ioat_internal.h Mon Dec 14 22:01:52 2015 (r292228)
@@ -373,6 +373,8 @@ struct ioat_softc {
struct resource *pci_resource;
uint32_t max_xfer_size;
uint32_t capabilities;
+ uint16_t intrdelay_max;
+ uint16_t cached_intrdelay;
struct resource *res;
int rid;
@@ -393,6 +395,7 @@ struct ioat_softc {
boolean_t is_completion_pending;
boolean_t is_reset_pending;
boolean_t is_channel_running;
+ boolean_t intrdelay_supported;
uint32_t head;
uint32_t tail;
More information about the svn-src-head
mailing list