Date: Tue, 3 May 2016 17:07:18 +0000 (UTC) From: "Conrad E. Meyer" <cem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r298989 - in head: share/man/man4 sys/dev/ioat Message-ID: <201605031707.u43H7IHE011955@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: cem Date: Tue May 3 17:07:18 2016 New Revision: 298989 URL: https://svnweb.freebsd.org/changeset/base/298989 Log: ioat(4): Implement CRC and MOVECRC APIs And document them in ioat.4. 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 Modified: head/share/man/man4/ioat.4 ============================================================================== --- head/share/man/man4/ioat.4 Tue May 3 17:06:33 2016 (r298988) +++ head/share/man/man4/ioat.4 Tue May 3 17:07:18 2016 (r298989) @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 14, 2016 +.Dd May 3, 2016 .Dt IOAT 4 .Os .Sh NAME @@ -99,6 +99,29 @@ In .Fa "uint32_t flags" .Fc .Ft struct bus_dmadesc * +.Fo ioat_copy_crc +.Fa "bus_dmaengine_t dmaengine" +.Fa "bus_addr_t dst" +.Fa "bus_addr_t src" +.Fa "bus_size_t len" +.Fa "uint32_t *initialseed" +.Fa "bus_addr_t crcptr" +.Fa "bus_dmaengine_callback_t callback_fn" +.Fa "void *callback_arg" +.Fa "uint32_t flags" +.Fc +.Ft struct bus_dmadesc * +.Fo ioat_crc +.Fa "bus_dmaengine_t dmaengine" +.Fa "bus_addr_t src" +.Fa "bus_size_t len" +.Fa "uint32_t *initialseed" +.Fa "bus_addr_t crcptr" +.Fa "bus_dmaengine_callback_t callback_fn" +.Fa "void *callback_arg" +.Fa "uint32_t flags" +.Fc +.Ft struct bus_dmadesc * .Fo ioat_blockfill .Fa "bus_dmaengine_t dmaengine" .Fa "bus_addr_t dst" @@ -183,6 +206,43 @@ from. It is invalid to attempt to submit new DMA operations in a .Fa bus_dmaengine_callback_t context. +.Pp +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. +.Pp +The +.Ar DMA_CRC_STORE +flag causes the operation to emit the CRC32C result. +If +.Ar DMA_CRC_INLINE +is set, the result is written inline with the destination data (or source in +.Fn ioat_crc +mode). +If +.Ar DMA_CRC_INLINE +is not set, the result is written to the provided +.Fa crcptr . +.Pp +Similarly, the +.Ar DMA_CRC_TEST +flag causes the operation to compare the CRC32C result to an existing checksum. +If +.Ar 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 +.Fa crcptr . +.Pp +.Fn ioat_copy_crc +calculates a CRC32C while copying data. +.Fn ioat_crc +only computes a CRC32C of some data. +If the +.Fa initialseed +argument to either routine is non-NULL, the CRC32C engine is initialized with +the value it points to. .Sh USAGE A typical user will lookup the DMA engine object for a given channel with .Fn ioat_get_dmaengine . @@ -199,9 +259,13 @@ If succeeds, there is guaranteed to be room for .Fa N new operations in the internal ring buffer. +.Pp Then, they will submit one or more operations using .Fn ioat_blockfill , .Fn ioat_copy , +.Fn ioat_copy_8k_aligned , +.Fn ioat_copy_crc , +.Fn ioat_crc , or .Fn ioat_null . After queuing one or more individual DMA operations, they will Modified: head/sys/dev/ioat/ioat.c ============================================================================== --- head/sys/dev/ioat/ioat.c Tue May 3 17:06:33 2016 (r298988) +++ head/sys/dev/ioat/ioat.c Tue May 3 17:07:18 2016 (r298989) @@ -882,8 +882,8 @@ ioat_op_generic(struct ioat_softc *ioat, 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 dma } 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) Modified: head/sys/dev/ioat/ioat.h ============================================================================== --- head/sys/dev/ioat/ioat.h Tue May 3 17:06:33 2016 (r298988) +++ head/sys/dev/ioat/ioat.h Tue May 3 17:07:18 2016 (r298989) @@ -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_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. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201605031707.u43H7IHE011955>