---
name: "ioat"
section: "4"
platform: "freebsd"
package: "base"
version: "16.0-CURRENT-20261027-61c70dc16a79"
release: "FreeBSD 16.0-CURRENT (2026-10-27)"
platforms: ["freebsd"]
url: "https://new.carta.tech/ioat"
---

# ioat(4)

Intel I/O Acceleration Technology

## NAME

**I/OAT** – Intel I/O Acceleration Technology

## SYNOPSIS

To compile this driver into your kernel, place the following line in your kernel configuration file:

**device ioat**

Or, to load the driver as a module at boot, place the following line in [loader.conf(5)](/loader.conf/5.md):

```
ioat_load="YES"
```

In [loader.conf(5)](/loader.conf/5.md):

**hw.ioat.force\_legacy\_interrupts=0**

In [loader.conf(5)](/loader.conf/5.md) or [sysctl.conf(5)](/sysctl.conf/5.md):

**hw.ioat.enable\_ioat\_test=0** **hw.ioat.debug\_level=0** (only critical errors; maximum of 3)

*typedef* *void*\

**(\*bus\_dmaengine\_callback\_t)**(*void \*arg*, *int error*);

*bus\_dmaengine\_t*\

**ioat\_get\_dmaengine**(*uint32\_t channel\_index*);

*void*\

**ioat\_put\_dmaengine**(*bus\_dmaengine\_t dmaengine*);

*int*\

**ioat\_get\_hwversion**(*bus\_dmaengine\_t dmaengine*);

*size\_t*\

**ioat\_get\_max\_io\_size**(*bus\_dmaengine\_t dmaengine*);

*int*\

**ioat\_set\_interrupt\_coalesce**(*bus\_dmaengine\_t dmaengine*, *uint16\_t delay*);

*uint16\_t*\

**ioat\_get\_max\_coalesce\_period**(*bus\_dmaengine\_t dmaengine*);

*void*\

**ioat\_acquire**(*bus\_dmaengine\_t dmaengine*);

*int*\

**ioat\_acquire\_reserve**(*bus\_dmaengine\_t dmaengine*, *uint32\_t n*, *int mflags*);

*void*\

**ioat\_release**(*bus\_dmaengine\_t dmaengine*);

*struct* *bus\_dmadesc* *\**\

**ioat\_copy**(*bus\_dmaengine\_t dmaengine*, *bus\_addr\_t dst*, *bus\_addr\_t src*, *bus\_size\_t len*, *bus\_dmaengine\_callback\_t callback\_fn*, *void \*callback\_arg*, *uint32\_t flags*);

*struct* *bus\_dmadesc* *\**\

**ioat\_copy\_8k\_aligned**(*bus\_dmaengine\_t dmaengine*, *bus\_addr\_t dst1*, *bus\_addr\_t dst2*, *bus\_addr\_t src1*, *bus\_addr\_t src2*, *bus\_dmaengine\_callback\_t callback\_fn*, *void \*callback\_arg*, *uint32\_t flags*);

*struct* *bus\_dmadesc* *\**\

**ioat\_copy\_crc**(*bus\_dmaengine\_t dmaengine*, *bus\_addr\_t dst*, *bus\_addr\_t src*, *bus\_size\_t len*, *uint32\_t \*initialseed*, *bus\_addr\_t crcptr*, *bus\_dmaengine\_callback\_t callback\_fn*, *void \*callback\_arg*, *uint32\_t flags*);

*struct* *bus\_dmadesc* *\**\

**ioat\_crc**(*bus\_dmaengine\_t dmaengine*, *bus\_addr\_t src*, *bus\_size\_t len*, *uint32\_t \*initialseed*, *bus\_addr\_t crcptr*, *bus\_dmaengine\_callback\_t callback\_fn*, *void \*callback\_arg*, *uint32\_t flags*);

*struct* *bus\_dmadesc* *\**\

**ioat\_blockfill**(*bus\_dmaengine\_t dmaengine*, *bus\_addr\_t dst*, *uint64\_t fillpattern*, *bus\_size\_t len*, *bus\_dmaengine\_callback\_t callback\_fn*, *void \*callback\_arg*, *uint32\_t flags*);

*struct* *bus\_dmadesc* *\**\

**ioat\_null**(*bus\_dmaengine\_t dmaengine*, *bus\_dmaengine\_callback\_t callback\_fn*, *void \*callback\_arg*, *uint32\_t flags*);

## DESCRIPTION

The **I/OAT** driver provides a kernel API to a variety of DMA engines on some Intel server platforms.

There is a number of DMA channels per CPU package. (Typically 4 or 8.) Each may be used independently. Operations on a single channel proceed sequentially.

Blockfill operations can be used to write a 64-bit pattern to memory.

Copy operations can be used to offload memory copies to the DMA engines.

Null operations do nothing, but may be used to test the interrupt and callback mechanism.

All operations can optionally trigger an interrupt at completion with the *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.

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 **ioat\_set\_interrupt\_coalesce**() API. The **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.

All operations are safe to use in a non-blocking context with the *DMA\_NO\_WAIT* flag. (Of course, allocations may fail and operations requested with *DMA\_NO\_WAIT* may return NULL.)

Operations that depend on the result of prior operations should use *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 *DMA\_FENCE*.

All operations, as well as **ioat\_get\_dmaengine**(), can return NULL in special circumstances. For example, if the **I/OAT** driver is being unloaded, or the administrator has induced a hardware reset, or a usage error has resulted in a hardware error state that needs to be recovered from.

It is invalid to attempt to submit new DMA operations in a *bus\_dmaengine\_callback\_t* context.

The CRC operations have three distinct modes. The default mode is to accumulate. By accumulating over multiple descriptors, a user may gather a CRC over several chunks of memory and only write out the result once.

The *DMA\_CRC\_STORE* flag causes the operation to emit the CRC32C result. If *DMA\_CRC\_INLINE* is set, the result is written inline with the destination data (or source in **ioat\_crc**() mode). If *DMA\_CRC\_INLINE* is not set, the result is written to the provided *crcptr*.

Similarly, the *DMA\_CRC\_TEST* flag causes the operation to compare the CRC32C result to an existing checksum. If *DMA\_CRC\_INLINE* is set, the result is compared against the inline four bytes trailing the source data. If it is not set, the result is compared against the value pointed to by *crcptr*.

**ioat\_copy\_crc**() calculates a CRC32C while copying data. **ioat\_crc**() only computes a CRC32C of some data. If the *initialseed* argument to either routine is non-NULL, the CRC32C engine is initialized with the value it points to.

## USAGE

A typical user will lookup the DMA engine object for a given channel with **ioat\_get\_dmaengine**(). When the user wants to offload a copy, they will first **ioat\_acquire**() the *bus\_dmaengine\_t* object for exclusive access to enqueue operations on that channel. Optionally, the user can reserve space by using **ioat\_acquire\_reserve**() instead. If **ioat\_acquire\_reserve**() succeeds, there is guaranteed to be room for *N* new operations in the internal ring buffer.

Then, they will submit one or more operations using **ioat\_blockfill**(), **ioat\_copy**(), **ioat\_copy\_8k\_aligned**(), **ioat\_copy\_crc**(), **ioat\_crc**(), or **ioat\_null**(). After queuing one or more individual DMA operations, they will **ioat\_release**() the *bus\_dmaengine\_t* to drop their exclusive access to the channel. The routine they provided for the *callback\_fn* argument will be invoked with the provided *callback\_arg* when the operation is complete. When they are finished with the *bus\_dmaengine\_t*, the user should **ioat\_put\_dmaengine**().

Users MUST NOT block between **ioat\_acquire**() and **ioat\_release**(). Users SHOULD NOT hold *bus\_dmaengine\_t* references for a very long time to enable fault recovery and kernel module unload.

For an example of usage, see *src/sys/dev/ioat/ioat\_test.c*.

## FILES

- */dev/ioat\_test*

  test device for ioatcontrol(8)

## SEE ALSO

ioatcontrol(8)

## HISTORY

The **I/OAT** driver first appeared in FreeBSD 11.0.

## AUTHORS

The **I/OAT** driver was developed by Jim Harris ⟨*jimharris@FreeBSD.org*⟩, Carl Delsey ⟨*carl.r.delsey@intel.com*⟩, and Conrad Meyer ⟨*cem@FreeBSD.org*⟩. This manual page was written by Conrad Meyer ⟨*cem@FreeBSD.org*⟩.

## CAVEATS

Copy operation takes bus addresses as parameters, not virtual addresses.

Buffers for individual copy operations must be physically contiguous.

Copies larger than max transfer size (1MB, but may vary by hardware) are not supported. Future versions will likely support this by breaking up the transfer into smaller sizes.

## BUGS

The **I/OAT** driver only supports blockfill, copy, and null operations at this time. The driver does not yet support advanced DMA modes, such as XOR, that some I/OAT devices support.
