aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ioat
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2016-05-03 17:07:18 +0000
committerConrad Meyer <cem@FreeBSD.org>2016-05-03 17:07:18 +0000
commitbec7ff798a8688da71c4b29d426a0cc887be677c (patch)
tree0fe5521f761cefcf4c1333fad7f1cbec4a1593a8 /sys/dev/ioat
parentbe3cbf60a5f034a5daadb49b5b79455e956ca601 (diff)
downloadsrc-bec7ff798a8688da71c4b29d426a0cc887be677c.tar.gz
src-bec7ff798a8688da71c4b29d426a0cc887be677c.zip
ioat(4): Implement CRC and MOVECRC APIs
And document them in ioat.4. Sponsored by: EMC / Isilon Storage Division
Notes
Notes: svn path=/head/; revision=298989
Diffstat (limited to 'sys/dev/ioat')
-rw-r--r--sys/dev/ioat/ioat.c162
-rw-r--r--sys/dev/ioat/ioat.h57
2 files changed, 216 insertions, 3 deletions
diff --git a/sys/dev/ioat/ioat.c b/sys/dev/ioat/ioat.c
index 1131f48f5017..faf6cb48a9f3 100644
--- a/sys/dev/ioat/ioat.c
+++ b/sys/dev/ioat/ioat.c
@@ -882,8 +882,8 @@ ioat_op_generic(struct ioat_softc *ioat, uint8_t op,
mtx_assert(&ioat->submit_lock, MA_OWNED);
- KASSERT((flags & ~DMA_ALL_FLAGS) == 0, ("Unrecognized flag(s): %#x",
- flags & ~DMA_ALL_FLAGS));
+ KASSERT((flags & ~_DMA_GENERIC_FLAGS) == 0,
+ ("Unrecognized flag(s): %#x", flags & ~_DMA_GENERIC_FLAGS));
if ((flags & DMA_NO_WAIT) != 0)
mflags = M_NOWAIT;
else
@@ -1018,6 +1018,164 @@ ioat_copy_8k_aligned(bus_dmaengine_t dmaengine, bus_addr_t dst1,
}
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 ioat_crc32_hw_descriptor *hw_desc;
+ struct ioat_descriptor *desc;
+ struct ioat_softc *ioat;
+ uint32_t teststore;
+ uint8_t op;
+
+ CTR0(KTR_IOAT, __func__);
+ ioat = to_ioat_softc(dmaengine);
+
+ if ((ioat->capabilities & IOAT_DMACAP_MOVECRC) == 0) {
+ ioat_log_message(0, "%s: Device lacks MOVECRC capability\n",
+ __func__);
+ return (NULL);
+ }
+ if (((src | dst) & (0xffffffull << 40)) != 0) {
+ ioat_log_message(0, "%s: High 24 bits of src/dst invalid\n",
+ __func__);
+ return (NULL);
+ }
+ teststore = (flags & _DMA_CRC_TESTSTORE);
+ if (teststore == _DMA_CRC_TESTSTORE) {
+ ioat_log_message(0, "%s: TEST and STORE invalid\n", __func__);
+ return (NULL);
+ }
+ if (teststore == 0 && (flags & DMA_CRC_INLINE) != 0) {
+ ioat_log_message(0, "%s: INLINE invalid without TEST or STORE\n",
+ __func__);
+ return (NULL);
+ }
+
+ switch (teststore) {
+ case DMA_CRC_STORE:
+ op = IOAT_OP_MOVECRC_STORE;
+ break;
+ case DMA_CRC_TEST:
+ op = IOAT_OP_MOVECRC_TEST;
+ break;
+ default:
+ KASSERT(teststore == 0, ("bogus"));
+ op = IOAT_OP_MOVECRC;
+ break;
+ }
+
+ if ((flags & DMA_CRC_INLINE) == 0 &&
+ (crcptr & (0xffffffull << 40)) != 0) {
+ ioat_log_message(0,
+ "%s: High 24 bits of crcptr invalid\n", __func__);
+ return (NULL);
+ }
+
+ desc = ioat_op_generic(ioat, op, len, src, dst, callback_fn,
+ callback_arg, flags & ~_DMA_CRC_FLAGS);
+ if (desc == NULL)
+ return (NULL);
+
+ hw_desc = desc->u.crc32;
+
+ if ((flags & DMA_CRC_INLINE) == 0)
+ hw_desc->crc_address = crcptr;
+ else
+ hw_desc->u.control.crc_location = 1;
+
+ if (initialseed != NULL) {
+ hw_desc->u.control.use_seed = 1;
+ hw_desc->seed = *initialseed;
+ }
+
+ if (g_ioat_debug_level >= 3)
+ dump_descriptor(hw_desc);
+
+ ioat_submit_single(ioat);
+ return (&desc->bus_dmadesc);
+}
+
+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 ioat_crc32_hw_descriptor *hw_desc;
+ struct ioat_descriptor *desc;
+ struct ioat_softc *ioat;
+ uint32_t teststore;
+ uint8_t op;
+
+ CTR0(KTR_IOAT, __func__);
+ ioat = to_ioat_softc(dmaengine);
+
+ if ((ioat->capabilities & IOAT_DMACAP_CRC) == 0) {
+ ioat_log_message(0, "%s: Device lacks CRC capability\n",
+ __func__);
+ return (NULL);
+ }
+ if ((src & (0xffffffull << 40)) != 0) {
+ ioat_log_message(0, "%s: High 24 bits of src invalid\n",
+ __func__);
+ return (NULL);
+ }
+ teststore = (flags & _DMA_CRC_TESTSTORE);
+ if (teststore == _DMA_CRC_TESTSTORE) {
+ ioat_log_message(0, "%s: TEST and STORE invalid\n", __func__);
+ return (NULL);
+ }
+ if (teststore == 0 && (flags & DMA_CRC_INLINE) != 0) {
+ ioat_log_message(0, "%s: INLINE invalid without TEST or STORE\n",
+ __func__);
+ return (NULL);
+ }
+
+ switch (teststore) {
+ case DMA_CRC_STORE:
+ op = IOAT_OP_CRC_STORE;
+ break;
+ case DMA_CRC_TEST:
+ op = IOAT_OP_CRC_TEST;
+ break;
+ default:
+ KASSERT(teststore == 0, ("bogus"));
+ op = IOAT_OP_CRC;
+ break;
+ }
+
+ if ((flags & DMA_CRC_INLINE) == 0 &&
+ (crcptr & (0xffffffull << 40)) != 0) {
+ ioat_log_message(0,
+ "%s: High 24 bits of crcptr invalid\n", __func__);
+ return (NULL);
+ }
+
+ desc = ioat_op_generic(ioat, op, len, src, 0, callback_fn,
+ callback_arg, flags & ~_DMA_CRC_FLAGS);
+ if (desc == NULL)
+ return (NULL);
+
+ hw_desc = desc->u.crc32;
+
+ if ((flags & DMA_CRC_INLINE) == 0)
+ hw_desc->crc_address = crcptr;
+ else
+ hw_desc->u.control.crc_location = 1;
+
+ if (initialseed != NULL) {
+ hw_desc->u.control.use_seed = 1;
+ hw_desc->seed = *initialseed;
+ }
+
+ if (g_ioat_debug_level >= 3)
+ dump_descriptor(hw_desc);
+
+ ioat_submit_single(ioat);
+ return (&desc->bus_dmadesc);
+}
+
+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)
diff --git a/sys/dev/ioat/ioat.h b/sys/dev/ioat/ioat.h
index ff0560217737..2e1012453bf0 100644
--- a/sys/dev/ioat/ioat.h
+++ b/sys/dev/ioat/ioat.h
@@ -52,7 +52,26 @@ __FBSDID("$FreeBSD$");
* may be prefetched before operation 1 completes.
*/
#define DMA_FENCE 0x4
-#define DMA_ALL_FLAGS (DMA_INT_EN | DMA_NO_WAIT | DMA_FENCE)
+#define _DMA_GENERIC_FLAGS (DMA_INT_EN | DMA_NO_WAIT | DMA_FENCE)
+
+/*
+ * Emit a CRC32C as the result of a ioat_copy_crc() or ioat_crc().
+ */
+#define DMA_CRC_STORE 0x8
+
+/*
+ * Compare the CRC32C of a ioat_copy_crc() or ioat_crc() against an expeceted
+ * value. It is invalid to specify both TEST and STORE.
+ */
+#define DMA_CRC_TEST 0x10
+#define _DMA_CRC_TESTSTORE (DMA_CRC_STORE | DMA_CRC_TEST)
+
+/*
+ * Use an inline comparison CRC32C or emit an inline CRC32C result. Invalid
+ * without one of STORE or TEST.
+ */
+#define DMA_CRC_INLINE 0x20
+#define _DMA_CRC_FLAGS (DMA_CRC_STORE | DMA_CRC_TEST | DMA_CRC_INLINE)
/*
* Hardware revision number. Different hardware revisions support different
@@ -152,6 +171,42 @@ struct bus_dmadesc *ioat_copy_8k_aligned(bus_dmaengine_t dmaengine,
bus_dmaengine_callback_t callback_fn, void *callback_arg, uint32_t flags);
/*
+ * Copy len bytes from dst to src, like ioat_copy().
+ *
+ * Additionally, accumulate a CRC32C of the data.
+ *
+ * If initialseed is not NULL, the value it points to is used to seed the
+ * initial value of the CRC32C.
+ *
+ * If flags include DMA_CRC_STORE and not DMA_CRC_INLINE, crcptr is written
+ * with the 32-bit CRC32C result (in wire format).
+ *
+ * If flags include DMA_CRC_TEST and not DMA_CRC_INLINE, the computed CRC32C is
+ * compared with the 32-bit CRC32C pointed to by crcptr. If they do not match,
+ * a channel error is raised.
+ *
+ * If the DMA_CRC_INLINE flag is set, crcptr is ignored and the DMA engine uses
+ * the 4 bytes trailing the source data (TEST) or the destination data (STORE).
+ */
+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);
+
+/*
+ * ioat_crc() is nearly identical to ioat_copy_crc(), but does not actually
+ * move data around.
+ *
+ * Like ioat_copy_crc, ioat_crc computes a CRC32C over len bytes pointed to by
+ * src. The flags affect its operation in the same way, with one exception:
+ *
+ * If flags includes both DMA_CRC_STORE and DMA_CRC_INLINE, the computed CRC32C
+ * is written to the 4 bytes trailing the *source* data.
+ */
+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);
+
+/*
* Issues a null operation. This issues the operation to the hardware, but the
* hardware doesn't do anything with it.
*/