xref: /freebsd/share/man/man9/bus_dma.9 (revision 315ee00f)
1.\" Copyright (c) 2002, 2003 Hiten M. Pandya.
2.\" All rights reserved.
3.\"
4.\" Redistribution and use in source and binary forms, with or without
5.\" modification, are permitted provided that the following conditions
6.\" are met:
7.\" 1. Redistributions of source code must retain the above copyright
8.\"    notice, this list of conditions, and the following disclaimer,
9.\"    without modification, immediately at the beginning of the file.
10.\" 2. The name of the author may not be used to endorse or promote products
11.\"    derived from this software without specific prior written permission.
12.\"
13.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, CONTRIBUTORS OR THE
17.\" VOICES IN HITEN PANDYA'S HEAD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
19.\" TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20.\" PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22.\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23.\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24.\"
25.\" Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc.
26.\" All rights reserved.
27.\"
28.\" This code is derived from software contributed to The NetBSD Foundation
29.\" by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
30.\" NASA Ames Research Center.
31.\"
32.\" Redistribution and use in source and binary forms, with or without
33.\" modification, are permitted provided that the following conditions
34.\" are met:
35.\" 1. Redistributions of source code must retain the above copyright
36.\"    notice, this list of conditions and the following disclaimer.
37.\" 2. Redistributions in binary form must reproduce the above copyright
38.\"    notice, this list of conditions and the following disclaimer in the
39.\"    documentation and/or other materials provided with the distribution.
40.\"
41.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
42.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
43.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
45.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
46.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
47.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
48.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
49.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
51.\" POSSIBILITY OF SUCH DAMAGE.
52.\" $NetBSD: bus_dma.9,v 1.25 2002/10/14 13:43:16 wiz Exp $
53.\"
54.Dd May 25, 2020
55.Dt BUS_DMA 9
56.Os
57.Sh NAME
58.Nm bus_dma ,
59.Nm bus_dma_tag_create ,
60.Nm bus_dma_tag_destroy ,
61.Nm bus_dma_template_init ,
62.Nm bus_dma_template_tag ,
63.Nm bus_dma_template_clone ,
64.Nm bus_dma_template_fill ,
65.Nm BUS_DMA_TEMPLATE_FILL ,
66.Nm bus_dmamap_create ,
67.Nm bus_dmamap_destroy ,
68.Nm bus_dmamap_load ,
69.Nm bus_dmamap_load_bio ,
70.Nm bus_dmamap_load_ccb ,
71.Nm bus_dmamap_load_crp ,
72.Nm bus_dmamap_load_crp_buffer ,
73.Nm bus_dmamap_load_mbuf ,
74.Nm bus_dmamap_load_mbuf_sg ,
75.Nm bus_dmamap_load_uio ,
76.Nm bus_dmamap_unload ,
77.Nm bus_dmamap_sync ,
78.Nm bus_dmamem_alloc ,
79.Nm bus_dmamem_free
80.Nd Bus and Machine Independent DMA Mapping Interface
81.Sh SYNOPSIS
82.In machine/bus.h
83.Ft int
84.Fn bus_dma_tag_create "bus_dma_tag_t parent" "bus_size_t alignment" \
85"bus_addr_t boundary" "bus_addr_t lowaddr" "bus_addr_t highaddr" \
86"bus_dma_filter_t *filtfunc" "void *filtfuncarg" "bus_size_t maxsize" \
87"int nsegments" "bus_size_t maxsegsz" "int flags" "bus_dma_lock_t *lockfunc" \
88"void *lockfuncarg" "bus_dma_tag_t *dmat"
89.Ft int
90.Fn bus_dma_tag_destroy "bus_dma_tag_t dmat"
91.Ft void
92.Fo bus_dma_template_init
93.Fa "bus_dma_template_t *template"
94.Fa "bus_dma_tag_t parent"
95.Fc
96.Ft int
97.Fo bus_dma_template_tag
98.Fa "bus_dma_template_t *template"
99.Fa "bus_dma_tag_t *dmat"
100.Fc
101.Ft void
102.Fo bus_dma_template_clone
103.Fa "bus_dma_template_t *template"
104.Fa "bus_dma_tag_t dmat"
105.Fc
106.Ft void
107.Fo bus_dma_template_fill
108.Fa "bus_dma_template_t *template"
109.Fa "bus_dma_param_t params[]"
110.Fa "u_int count"
111.Fc
112.Fo BUS_DMA_TEMPLATE_FILL
113.Fa "bus_dma_template_t *template"
114.Fa "bus_dma_param_t param ..."
115.Fc
116.Ft int
117.Fn bus_dmamap_create "bus_dma_tag_t dmat" "int flags" "bus_dmamap_t *mapp"
118.Ft int
119.Fn bus_dmamap_destroy "bus_dma_tag_t dmat" "bus_dmamap_t map"
120.Ft int
121.Fn bus_dmamap_load "bus_dma_tag_t dmat" "bus_dmamap_t map" "void *buf" \
122"bus_size_t buflen" "bus_dmamap_callback_t *callback" "void *callback_arg" \
123"int flags"
124.Ft int
125.Fn bus_dmamap_load_bio "bus_dma_tag_t dmat" "bus_dmamap_t map" \
126"struct bio *bio" "bus_dmamap_callback_t *callback" "void *callback_arg" \
127"int flags"
128.Ft int
129.Fn bus_dmamap_load_ccb "bus_dma_tag_t dmat" "bus_dmamap_t map" \
130"union ccb *ccb" "bus_dmamap_callback_t *callback" "void *callback_arg" \
131"int flags"
132.Ft int
133.Fn bus_dmamap_load_crp "bus_dma_tag_t dmat" "bus_dmamap_t map" \
134"struct crypto *crp" "bus_dmamap_callback_t *callback" "void *callback_arg" \
135"int flags"
136.Ft int
137.Fn bus_dmamap_load_crp_buffer "bus_dma_tag_t dmat" "bus_dmamap_t map" \
138"struct crypto_buffer *cb" "bus_dmamap_callback_t *callback" \
139"void *callback_arg" "int flags"
140.Ft int
141.Fn bus_dmamap_load_mbuf "bus_dma_tag_t dmat" "bus_dmamap_t map" \
142"struct mbuf *mbuf" "bus_dmamap_callback2_t *callback" "void *callback_arg" \
143"int flags"
144.Ft int
145.Fn bus_dmamap_load_mbuf_sg "bus_dma_tag_t dmat" "bus_dmamap_t map" \
146"struct mbuf *mbuf" "bus_dma_segment_t *segs" "int *nsegs" "int flags"
147.Ft int
148.Fn bus_dmamap_load_uio "bus_dma_tag_t dmat" "bus_dmamap_t map" \
149"struct uio *uio" "bus_dmamap_callback2_t *callback" "void *callback_arg" \
150"int flags"
151.Ft void
152.Fn bus_dmamap_unload "bus_dma_tag_t dmat" "bus_dmamap_t map"
153.Ft void
154.Fn bus_dmamap_sync "bus_dma_tag_t dmat" "bus_dmamap_t map" \
155"op"
156.Ft int
157.Fn bus_dmamem_alloc "bus_dma_tag_t dmat" "void **vaddr" \
158"int flags" "bus_dmamap_t *mapp"
159.Ft void
160.Fn bus_dmamem_free "bus_dma_tag_t dmat" "void *vaddr" \
161"bus_dmamap_t map"
162.Sh DESCRIPTION
163Direct Memory Access (DMA) is a method of transferring data
164without involving the CPU, thus providing higher performance.
165A DMA transaction can be achieved between device to memory,
166device to device, or memory to memory.
167.Pp
168The
169.Nm
170API is a bus, device, and machine-independent (MI) interface to
171DMA mechanisms.
172It provides the client with flexibility and simplicity by
173abstracting machine dependent issues like setting up
174DMA mappings, handling cache issues, bus specific features
175and limitations.
176.Sh OVERVIEW
177A tag structure
178.Vt ( bus_dma_tag_t )
179is used to describe the properties of a group of related DMA
180transactions.
181One way to view this is that a tag describes the limitations of a DMA engine.
182For example, if a DMA engine in a device is limited to 32-bit addresses,
183that limitation is specified by a parameter when creating the tag
184for that device.
185Similarly, a tag can be marked as requiring buffers whose addresses are
186aligned to a specific boundary.
187.Pp
188Some devices may require multiple tags to describe DMA
189transactions with differing properties.
190For example, a device might require 16-byte alignment of its descriptor ring
191while permitting arbitrary alignment of I/O buffers.
192In this case,
193the driver must create one tag for the descriptor ring and a separate tag for
194I/O buffers.
195If a device has restrictions that are common to all DMA transactions
196in addition to restrictions that differ between unrelated groups of
197transactions,
198the driver can first create a
199.Dq parent
200tag that decribes the common restrictions.
201The per-group tags can then inherit these restrictions from this
202.Dq parent
203tag rather than having to list them explicitly when creating the per-group tags.
204.Pp
205A mapping structure
206.Vt ( bus_dmamap_t )
207represents a mapping of a memory region for DMA.
208On systems with I/O MMUs,
209the mapping structure tracks any I/O MMU entries used by a request.
210For DMA requests that require bounce pages,
211the mapping tracks the bounce pages used.
212.Pp
213To prepare for one or more DMA transactions,
214a mapping must be bound to a memory region by calling one of the
215.Fn bus_dmamap_load
216functions.
217These functions configure the mapping which can include programming entries
218in an I/O MMU and/or allocating bounce pages.
219An output of these functions
220(either directly or indirectly by invoking a callback routine)
221is the list of scatter/gather address ranges a consumer can pass to a DMA
222engine to access the memory region.
223When a mapping is no longer needed,
224the mapping must be unloaded via
225.Fn bus_dmamap_unload .
226.Pp
227Before and after each DMA transaction,
228.Fn bus_dmamap_sync
229must be used to ensure that the correct data is used by the DMA engine and
230the CPU.
231If a mapping uses bounce pages,
232the sync operations copy data between the bounce pages and the memory region
233bound to the mapping.
234Sync operations also handle architecture-specific details such as CPU cache
235flushing and CPU memory operation ordering.
236.Sh STATIC VS DYNAMIC
237.Nm
238handles two types of DMA transactions: static and dynamic.
239Static transactions are used with a long-lived memory region that is reused
240for many transactions such as a descriptor ring.
241Dynamic transactions are used for transfers to or from transient buffers
242such as I/O buffers holding a network packet or disk block.
243Each transaction type uses a different subset of the
244.Nm
245API.
246.Ss Static Transactions
247Static transactions use memory regions allocated by
248.Nm .
249Each static memory region is allocated by calling
250.Fn bus_dmamem_alloc .
251This function requires a valid tag describing the properties of the
252DMA transactions to this region such as alignment or address restrictions.
253Multiple regions can share a single tag if they share the same restrictions.
254.Pp
255.Fn bus_dmamem_alloc
256allocates a memory region along with a mapping object.
257The associated tag, memory region, and mapping object must then be passed to
258.Fn bus_dmamap_load
259to bind the mapping to the allocated region and obtain the
260scatter/gather list.
261.Pp
262It is expected that
263.Fn bus_dmamem_alloc
264will attempt to allocate memory requiring less expensive sync operations
265(for example, implementations should not allocate regions requiring bounce
266pages),
267but sync operations should still be used.
268For example, a driver should use
269.Fn bus_dmamap_sync
270in an interrupt handler before reading descriptor ring entries written by the
271device prior to the interrupt.
272.Pp
273When a consumer is finished with a memory region,
274it should unload the mapping via
275.Fn bus_dmamap_unload
276and then release the memory region and mapping object via
277.Fn bus_dmamem_free .
278.Ss Dynamic Transactions
279Dynamic transactions map memory regions provided by other parts of the system.
280A tag must be created via
281.Fn bus_dma_tag_create
282to describe the DMA transactions to and from these memory regions,
283and a pool of mapping objects must be allocated via
284.Fn bus_dmamap_create
285to track the mappings of any in-flight transactions.
286.Pp
287When a consumer wishes to schedule a transaction for a memory region,
288the consumer must first obtain an unused mapping object from its pool
289of mapping objects.
290The memory region must be bound to the mapping object via one of the
291.Fn bus_dmamap_load
292functions.
293Before scheduling the transaction,
294the consumer should sync the memory region via
295.Fn bus_dmamap_sync
296with one or more of the
297.Dq PRE
298flags.
299After the transaction has completed,
300the consumer should sync the memory region via
301.Fn bus_dmamap_sync
302with one or more of the
303.Dq POST
304flags.
305The mapping can then be unloaded via
306.Fn bus_dmamap_unload ,
307and the mapping object can be returned to the pool of unused mapping objects.
308.Pp
309When a consumer is no longer scheduling DMA transactions,
310the mapping objects should be freed via
311.Fn bus_dmamap_destroy ,
312and the tag should be freed via
313.Fn bus_dma_tag_destroy .
314.Sh STRUCTURES AND TYPES
315.Bl -tag -width indent
316.It Vt bus_dma_tag_t
317A machine-dependent (MD) opaque type that describes the
318characteristics of a group of DMA transactions.
319DMA tags are organized into a hierarchy, with each child
320tag inheriting the restrictions of its parent.
321This allows all devices along the path of DMA transactions
322to contribute to the constraints of those transactions.
323.It Vt bus_dma_template_t
324A template is a structure for creating a
325.Fa bus_dma_tag_t
326from a set of defaults.
327Once initialized with
328.Fn bus_dma_template_init ,
329a driver can over-ride individual fields to suit its needs.
330The following fields start with the indicated default values:
331.Bd -literal
332	alignment	1
333	boundary	0
334	lowaddr		BUS_SPACE_MAXADDR
335	highaddr	BUS_SPACE_MAXADDR
336	maxsize		BUS_SPACE_MAXSIZE
337	nsegments	BUS_SPACE_UNRESTRICTED
338	maxsegsize	BUS_SPACE_MAXSIZE
339	flags		0
340	lockfunc	NULL
341	lockfuncarg	NULL
342.Ed
343.Pp
344Descriptions of each field are documented with
345.Fn bus_dma_tag_create .
346Note that the
347.Fa filtfunc
348and
349.Fa filtfuncarg
350attributes of the DMA tag are not supported with templates.
351.It Vt bus_dma_filter_t
352Client specified address filter having the format:
353.Bl -tag -width indent
354.It Ft int
355.Fn "client_filter" "void *filtarg" "bus_addr_t testaddr"
356.El
357.Pp
358Address filters can be specified during tag creation to allow
359for devices whose DMA address restrictions cannot be specified
360by a single window.
361The
362.Fa filtarg
363argument is specified by the client during tag creation to be passed to all
364invocations of the callback.
365The
366.Fa testaddr
367argument contains a potential starting address of a DMA mapping.
368The filter function operates on the set of addresses from
369.Fa testaddr
370to
371.Ql trunc_page(testaddr) + PAGE_SIZE - 1 ,
372inclusive.
373The filter function should return zero if any mapping in this range
374can be accommodated by the device and non-zero otherwise.
375.Pp
376.Em Note: The use of filters is deprecated.  Proper operation is not guaranteed.
377.It Vt bus_dma_segment_t
378A machine-dependent type that describes individual
379DMA segments.
380It contains the following fields:
381.Bd -literal
382	bus_addr_t	ds_addr;
383	bus_size_t	ds_len;
384.Ed
385.Pp
386The
387.Fa ds_addr
388field contains the device visible address of the DMA segment, and
389.Fa ds_len
390contains the length of the DMA segment.
391Although the DMA segments returned by a mapping call will adhere to
392all restrictions necessary for a successful DMA operation, some conversion
393(e.g.\& a conversion from host byte order to the device's byte order) is
394almost always required when presenting segment information to the device.
395.It Vt bus_dmamap_t
396A machine-dependent opaque type describing an individual mapping.
397One map is used for each memory allocation that will be loaded.
398Maps can be reused once they have been unloaded.
399Multiple maps can be associated with one DMA tag.
400While the value of the map may evaluate to
401.Dv NULL
402on some platforms under certain conditions,
403it should never be assumed that it will be
404.Dv NULL
405in all cases.
406.It Vt bus_dmamap_callback_t
407Client specified callback for receiving mapping information resulting from
408the load of a
409.Vt bus_dmamap_t
410via
411.Fn bus_dmamap_load ,
412.Fn bus_dmamap_load_bio ,
413.Fn bus_dmamap_load_ccb ,
414.Fn bus_dmamap_load_crp ,
415or
416.Fn bus_dmamap_load_crp_buffer .
417Callbacks are of the format:
418.Bl -tag -width indent
419.It Ft void
420.Fn "client_callback" "void *callback_arg" "bus_dma_segment_t *segs" \
421"int nseg" "int error"
422.El
423.Pp
424The
425.Fa callback_arg
426is the callback argument passed to dmamap load functions.
427The
428.Fa segs
429and
430.Fa nseg
431arguments describe an array of
432.Vt bus_dma_segment_t
433structures that represent the mapping.
434This array is only valid within the scope of the callback function.
435The success or failure of the mapping is indicated by the
436.Fa error
437argument.
438More information on the use of callbacks can be found in the
439description of the individual dmamap load functions.
440.It Vt bus_dmamap_callback2_t
441Client specified callback for receiving mapping information resulting from
442the load of a
443.Vt bus_dmamap_t
444via
445.Fn bus_dmamap_load_uio
446or
447.Fn bus_dmamap_load_mbuf .
448.Pp
449Callback2s are of the format:
450.Bl -tag -width indent
451.It Ft void
452.Fn "client_callback2" "void *callback_arg" "bus_dma_segment_t *segs" \
453"int nseg" "bus_size_t mapsize" "int error"
454.El
455.Pp
456Callback2's behavior is the same as
457.Vt bus_dmamap_callback_t
458with the addition that the length of the data mapped is provided via
459.Fa mapsize .
460.It Vt bus_dmasync_op_t
461Memory synchronization operation specifier.
462Bus DMA requires explicit synchronization of memory with its device
463visible mapping in order to guarantee memory coherency.
464The
465.Vt bus_dmasync_op_t
466allows the type of DMA operation that will be or has been performed
467to be communicated to the system so that the correct coherency measures
468are taken.
469The operations are represented as bitfield flags that can be combined together,
470though it only makes sense to combine PRE flags or POST flags, not both.
471See the
472.Fn bus_dmamap_sync
473description below for more details on how to use these operations.
474.Pp
475All operations specified below are performed from the host memory point of view,
476where a read implies data coming from the device to the host memory, and a write
477implies data going from the host memory to the device.
478Alternatively, the operations can be thought of in terms of driver operations,
479where reading a network packet or storage sector corresponds to a read operation
480in
481.Nm .
482.Bl -tag -width ".Dv BUS_DMASYNC_POSTWRITE"
483.It Dv BUS_DMASYNC_PREREAD
484Perform any synchronization required prior to an update of host memory by the
485device.
486.It Dv BUS_DMASYNC_PREWRITE
487Perform any synchronization required after an update of host memory by the CPU
488and prior to device access to host memory.
489.It Dv BUS_DMASYNC_POSTREAD
490Perform any synchronization required after an update of host memory by the
491device and prior to CPU access to host memory.
492.It Dv BUS_DMASYNC_POSTWRITE
493Perform any synchronization required after device access to host memory.
494.El
495.It Vt bus_dma_lock_t
496Client specified lock/mutex manipulation method.
497This will be called from
498within busdma whenever a client lock needs to be manipulated.
499In its current form, the function will be called immediately before
500the callback for a DMA load operation that has been deferred with
501.Dv BUS_DMA_LOCK
502and immediately after with
503.Dv BUS_DMA_UNLOCK .
504If the load operation does not need to be deferred, then it
505will not be called since the function loading the map should
506be holding the appropriate locks.
507This method is of the format:
508.Bl -tag -width indent
509.It Ft void
510.Fn "lockfunc" "void *lockfunc_arg" "bus_dma_lock_op_t op"
511.El
512.Pp
513The
514.Fa lockfuncarg
515argument is specified by the client during tag creation to be passed to all
516invocations of the callback.
517The
518.Fa op
519argument specifies the lock operation to perform.
520.Pp
521Two
522.Vt lockfunc
523implementations are provided for convenience.
524.Fn busdma_lock_mutex
525performs standard mutex operations on the sleep mutex provided via
526.Fa lockfuncarg .
527.Fn dflt_lock
528will generate a system panic if it is called.
529It is substituted into the tag when
530.Fa lockfunc
531is passed as
532.Dv NULL
533to
534.Fn bus_dma_tag_create
535and is useful for tags that should not be used with deferred load operations.
536.It Vt bus_dma_lock_op_t
537Operations to be performed by the client-specified
538.Fn lockfunc .
539.Bl -tag -width ".Dv BUS_DMA_UNLOCK"
540.It Dv BUS_DMA_LOCK
541Acquires and/or locks the client locking primitive.
542.It Dv BUS_DMA_UNLOCK
543Releases and/or unlocks the client locking primitive.
544.El
545.El
546.Sh FUNCTIONS
547.Bl -tag -width indent
548.It Fn bus_dma_tag_create "parent" "alignment" "boundary" "lowaddr" \
549"highaddr" "*filtfunc" "*filtfuncarg" "maxsize" "nsegments" "maxsegsz" \
550"flags" "lockfunc" "lockfuncarg" "*dmat"
551Allocates a DMA tag, and initializes it according to
552the arguments provided:
553.Bl -tag -width ".Fa filtfuncarg"
554.It Fa parent
555A parent tag from which to inherit restrictions.
556The restrictions passed in other arguments can only further tighten the
557restrictions inherited from the parent tag.
558.Pp
559All tags created by a device driver must inherit from the tag returned by
560.Fn bus_get_dma_tag
561to honor restrictions between the parent bridge, CPU memory, and the
562device.
563.It Fa alignment
564Alignment constraint, in bytes, of any mappings created using this tag.
565The alignment must be a power of 2.
566Hardware that can DMA starting at any address would specify
567.Em 1
568for byte alignment.
569Hardware requiring DMA transfers to start on a multiple of 4K
570would specify
571.Em 4096 .
572.It Fa boundary
573Boundary constraint, in bytes, of the target DMA memory region.
574The boundary indicates the set of addresses, all multiples of the
575boundary argument, that cannot be crossed by a single
576.Vt bus_dma_segment_t .
577The boundary must be a power of 2 and must be no smaller than the
578maximum segment size.
579.Ql 0
580indicates that there are no boundary restrictions.
581.It Fa lowaddr , highaddr
582Bounds of the window of bus address space that
583.Em cannot
584be directly accessed by the device.
585The window contains all addresses greater than
586.Fa lowaddr
587and less than or equal to
588.Fa highaddr .
589For example, a device incapable of DMA above 4GB, would specify a
590.Fa highaddr
591of
592.Dv BUS_SPACE_MAXADDR
593and a
594.Fa lowaddr
595of
596.Dv BUS_SPACE_MAXADDR_32BIT .
597Similarly a device that can only perform DMA to addresses below
59816MB would specify a
599.Fa highaddr
600of
601.Dv BUS_SPACE_MAXADDR
602and a
603.Fa lowaddr
604of
605.Dv BUS_SPACE_MAXADDR_24BIT .
606Some implementations require that some region of device visible
607address space, overlapping available host memory, be outside the
608window.
609This area of
610.Ql safe memory
611is used to bounce requests that would otherwise conflict with
612the exclusion window.
613.It Fa filtfunc
614Optional filter function (may be
615.Dv NULL )
616to be called for any attempt to
617map memory into the window described by
618.Fa lowaddr
619and
620.Fa highaddr .
621A filter function is only required when the single window described
622by
623.Fa lowaddr
624and
625.Fa highaddr
626cannot adequately describe the constraints of the device.
627The filter function will be called for every machine page
628that overlaps the exclusion window.
629.Pp
630.Em Note: The use of filters is deprecated.  Proper operation is not guaranteed.
631.It Fa filtfuncarg
632Argument passed to all calls to the filter function for this tag.
633May be
634.Dv NULL .
635.It Fa maxsize
636Maximum size, in bytes, of the sum of all segment lengths in a given
637DMA mapping associated with this tag.
638.It Fa nsegments
639Number of discontinuities (scatter/gather segments) allowed
640in a DMA mapped region.
641.It Fa maxsegsz
642Maximum size, in bytes, of a segment in any DMA mapped region associated
643with
644.Fa dmat .
645.It Fa flags
646Are as follows:
647.Bl -tag -width ".Dv BUS_DMA_ALLOCNOW"
648.It Dv BUS_DMA_ALLOCNOW
649Pre-allocate enough resources to handle at least one map load operation on
650this tag.
651If sufficient resources are not available,
652.Er ENOMEM
653is returned.
654This should not be used for tags that only describe buffers that will be
655allocated with
656.Fn bus_dmamem_alloc .
657Also, due to resource sharing with other tags, this flag does not guarantee
658that resources will be allocated or reserved exclusively for this tag.
659It should be treated only as a minor optimization.
660.It Dv BUS_DMA_COHERENT
661Indicate that the DMA engine and CPU are cache-coherent.
662Cached memory may be used to back allocations created by
663.Fn bus_dmamem_alloc .
664For
665.Fn bus_dma_tag_create ,
666the
667.Dv BUS_DMA_COHERENT
668flag is currently implemented on arm64.
669.El
670.It Fa lockfunc
671Optional lock manipulation function (may be
672.Dv NULL )
673to be called when busdma
674needs to manipulate a lock on behalf of the client.
675If
676.Dv NULL
677is specified,
678.Fn dflt_lock
679is used.
680.It Fa lockfuncarg
681Optional argument to be passed to the function specified by
682.Fa lockfunc .
683.It Fa dmat
684Pointer to a bus_dma_tag_t where the resulting DMA tag will
685be stored.
686.El
687.Pp
688Returns
689.Er ENOMEM
690if sufficient memory is not available for tag creation
691or allocating mapping resources.
692.It Fn bus_dma_tag_destroy "dmat"
693Deallocate the DMA tag
694.Fa dmat
695that was created by
696.Fn bus_dma_tag_create .
697.Pp
698Returns
699.Er EBUSY
700if any DMA maps remain associated with
701.Fa dmat
702or
703.Ql 0
704on success.
705.It Fn bus_dma_template_init "*template" "parent"
706Initializes a
707.Fa bus_dma_template_t
708structure.
709If the
710.Fa parent
711argument is non-NULL, this parent tag is associated with the template and
712will be compiled into the dma tag that is later created.
713The values of the parent are not copied into the template.
714During tag creation in
715.Fn bus_dma_tag_template ,
716any parameters from the parent tag that are more restrictive than what is
717in the provided template will overwrite what goes into the new tag.
718.It Fn bus_dma_template_tag "*template" "*dmat"
719Unpacks a template into a tag, and returns the tag via the
720.Fa dmat .
721All return values are identical to
722.Fn bus_dma_tag_create .
723The template is not modified by this function, and can be reused and/or
724freed upon return.
725.It Fn bus_dma_template_clone "*template" "dmat"
726Copies the fields from an existing tag to a template.
727The template does not need to be initialized first.
728All of its fields will be overwritten by the values contained in the tag.
729When paired with
730.Fn bus_dma_template_tag ,
731this function is useful for creating copies of tags.
732.It Fn bus_dma_template_fill "*template" "params[]" "count"
733Fills in the selected fields of the template with the keyed values from the
734.Fa params
735array.
736This is not meant to be called directly, use
737.Fn BUS_DMA_TEMPLATE_FILL
738instead.
739.It Fn BUS_DMA_TEMPLATE_FILL "*template" "param ..."
740Fills in the selected fields of the template with a variable number of
741key-value parameters.
742The macros listed below take an argument of the specified type and encapsulate
743it into a key-value structure that is directly usable as a parameter argument.
744Muliple parameters may be provided at once.
745.Bd -literal
746	BD_PARENT()	void *
747	BD_ALIGNMENT()	uintmax_t
748	BD_BOUNDARY()	uintmax_t
749	BD_LOWADDR()	vm_paddr_t
750	BD_HIGHADDR()	vm_paddr_t
751	BD_MAXSIZE()	uintmax_t
752	BD_NSEGMENTS()	uintmax_t
753	BD_MAXSEGSIZE()	uintmax_t
754	BD_FLAGS()	uintmax_t
755	BD_LOCKFUNC()	void *
756	BD_LOCKFUNCARG() void *
757.Ed
758.It Fn bus_dmamap_create "dmat" "flags" "*mapp"
759Allocates and initializes a DMA map.
760Arguments are as follows:
761.Bl -tag -width ".Fa nsegments"
762.It Fa dmat
763DMA tag.
764.It Fa flags
765Are as follows:
766.Bl -tag -width ".Dv BUS_DMA_COHERENT"
767.It Dv BUS_DMA_COHERENT
768Attempt to map the memory loaded with this map such that cache sync
769operations are as cheap as possible.
770This flag is typically set on maps when the memory loaded with these will
771be accessed by both a CPU and a DMA engine, frequently such as control data
772and as opposed to streamable data such as receive and transmit buffers.
773Use of this flag does not remove the requirement of using
774.Fn bus_dmamap_sync ,
775but it may reduce the cost of performing these operations.
776.El
777.It Fa mapp
778Pointer to a
779.Vt bus_dmamap_t
780where the resulting DMA map will be stored.
781.El
782.Pp
783Returns
784.Er ENOMEM
785if sufficient memory is not available for creating the
786map or allocating mapping resources.
787.It Fn bus_dmamap_destroy "dmat" "map"
788Frees all resources associated with a given DMA map.
789Arguments are as follows:
790.Bl -tag -width ".Fa dmat"
791.It Fa dmat
792DMA tag used to allocate
793.Fa map .
794.It Fa map
795The DMA map to destroy.
796.El
797.Pp
798Returns
799.Er EBUSY
800if a mapping is still active for
801.Fa map .
802.It Fn bus_dmamap_load "dmat" "map" "buf" "buflen" "*callback" \
803"callback_arg" "flags"
804Creates a mapping in device visible address space of
805.Fa buflen
806bytes of
807.Fa buf ,
808associated with the DMA map
809.Fa map .
810This call will always return immediately and will not block for any reason.
811Arguments are as follows:
812.Bl -tag -width ".Fa buflen"
813.It Fa dmat
814DMA tag used to allocate
815.Fa map .
816.It Fa map
817A DMA map without a currently active mapping.
818.It Fa buf
819A kernel virtual address pointer to a contiguous (in KVA) buffer, to be
820mapped into device visible address space.
821.It Fa buflen
822The size of the buffer.
823.It Fa callback Fa callback_arg
824The callback function, and its argument.
825This function is called once sufficient mapping resources are available for
826the DMA operation.
827If resources are temporarily unavailable, this function will be deferred until
828later, but the load operation will still return immediately to the caller.
829Thus, callers should not assume that the callback will be called before the
830load returns, and code should be structured appropriately to handle this.
831See below for specific flags and error codes that control this behavior.
832.It Fa flags
833Are as follows:
834.Bl -tag -width ".Dv BUS_DMA_NOWAIT"
835.It Dv BUS_DMA_NOWAIT
836The load should not be deferred in case of insufficient mapping resources,
837and instead should return immediately with an appropriate error.
838.It Dv BUS_DMA_NOCACHE
839The generated transactions to and from the virtual page are non-cacheable.
840.El
841.El
842.Pp
843Return values to the caller are as follows:
844.Bl -tag -width ".Er EINPROGRESS"
845.It 0
846The callback has been called and completed.
847The status of the mapping has been delivered to the callback.
848.It Er EINPROGRESS
849The mapping has been deferred for lack of resources.
850The callback will be called as soon as resources are available.
851Callbacks are serviced in FIFO order.
852.Pp
853Note that subsequent load operations for the same tag that do not require
854extra resources will still succeed.
855This may result in out-of-order processing of requests.
856If the caller requires the order of requests to be preserved,
857then the caller is required to stall subsequent requests until a pending
858request's callback is invoked.
859.It Er ENOMEM
860The load request has failed due to insufficient resources, and the caller
861specifically used the
862.Dv BUS_DMA_NOWAIT
863flag.
864.It Er EINVAL
865The load request was invalid.
866The callback has been called and has been provided the same error.
867This error value may indicate that
868.Fa dmat ,
869.Fa map ,
870.Fa buf ,
871or
872.Fa callback
873were invalid, or
874.Fa buflen
875was larger than the
876.Fa maxsize
877argument used to create the dma tag
878.Fa dmat .
879.El
880.Pp
881When the callback is called, it is presented with an error value
882indicating the disposition of the mapping.
883Error may be one of the following:
884.Bl -tag -width ".Er EINPROGRESS"
885.It 0
886The mapping was successful and the
887.Fa dm_segs
888callback argument contains an array of
889.Vt bus_dma_segment_t
890elements describing the mapping.
891This array is only valid during the scope of the callback function.
892.It Er EFBIG
893A mapping could not be achieved within the segment constraints provided
894in the tag even though the requested allocation size was less than maxsize.
895.El
896.It Fn bus_dmamap_load_bio "dmat" "map" "bio" "callback" "callback_arg" "flags"
897This is a variation of
898.Fn bus_dmamap_load
899which maps buffers pointed to by
900.Fa bio
901for DMA transfers.
902.Fa bio
903may point to either a mapped or unmapped buffer.
904.It Fn bus_dmamap_load_ccb "dmat" "map" "ccb" "callback" "callback_arg" "flags"
905This is a variation of
906.Fn bus_dmamap_load
907which maps data pointed to by
908.Fa ccb
909for DMA transfers.
910The data for
911.Fa ccb
912may be any of the following types:
913.Bl -tag -width ".Er CAM_DATA_SG_PADDR"
914.It CAM_DATA_VADDR
915The data is a single KVA buffer.
916.It CAM_DATA_PADDR
917The data is a single bus address range.
918.It CAM_DATA_SG
919The data is a scatter/gather list of KVA buffers.
920.It CAM_DATA_SG_PADDR
921The data is a scatter/gather list of bus address ranges.
922.It CAM_DATA_BIO
923The data is contained in a
924.Vt struct bio
925attached to the CCB.
926.El
927.Pp
928.Fn bus_dmamap_load_ccb
929supports the following CCB XPT function codes:
930.Pp
931.Bl -item -offset indent -compact
932.It
933XPT_ATA_IO
934.It
935XPT_CONT_TARGET_IO
936.It
937XPT_SCSI_IO
938.El
939.It Fn bus_dmamap_load_crp "dmat" "map" "crp" "callback" "callback_arg" "flags"
940This is a variation of
941.Fn bus_dmamap_load
942which maps the input buffer pointed to by
943.Fa crp
944for DMA transfers.
945The
946.Dv BUS_DMA_NOWAIT
947flag is implied, thus no callback deferral will happen.
948.It Fn bus_dmamap_load_crp_buffer "dmat" "map" "cb" "callback" "callback_arg" \
949"flags"
950This is a variation of
951.Fn bus_dmamap_load
952which maps the crypto data buffer pointed to by
953.Fa cb
954for DMA transfers.
955The
956.Dv BUS_DMA_NOWAIT
957flag is implied, thus no callback deferral will happen.
958.It Fn bus_dmamap_load_mbuf "dmat" "map" "mbuf" "callback2" "callback_arg" \
959"flags"
960This is a variation of
961.Fn bus_dmamap_load
962which maps mbuf chains
963for DMA transfers.
964A
965.Vt bus_size_t
966argument is also passed to the callback routine, which
967contains the mbuf chain's packet header length.
968The
969.Dv BUS_DMA_NOWAIT
970flag is implied, thus no callback deferral will happen.
971.Pp
972Mbuf chains are assumed to be in kernel virtual address space.
973.Pp
974Beside the error values listed for
975.Fn bus_dmamap_load ,
976.Er EINVAL
977will be returned if the size of the mbuf chain exceeds the maximum limit of the
978DMA tag.
979.It Fn bus_dmamap_load_mbuf_sg "dmat" "map" "mbuf" "segs" "nsegs" "flags"
980This is just like
981.Fn bus_dmamap_load_mbuf
982except that it returns immediately without calling a callback function.
983It is provided for efficiency.
984The scatter/gather segment array
985.Va segs
986is provided by the caller and filled in directly by the function.
987The
988.Va nsegs
989argument is returned with the number of segments filled in.
990Returns the same errors as
991.Fn bus_dmamap_load_mbuf .
992.It Fn bus_dmamap_load_uio "dmat" "map" "uio" "callback2" "callback_arg" "flags"
993This is a variation of
994.Fn bus_dmamap_load
995which maps buffers pointed to by
996.Fa uio
997for DMA transfers.
998A
999.Vt bus_size_t
1000argument is also passed to the callback routine, which contains the size of
1001.Fa uio ,
1002i.e.
1003.Fa uio->uio_resid .
1004The
1005.Dv BUS_DMA_NOWAIT
1006flag is implied, thus no callback deferral will happen.
1007Returns the same errors as
1008.Fn bus_dmamap_load .
1009.Pp
1010If
1011.Fa uio->uio_segflg
1012is
1013.Dv UIO_USERSPACE ,
1014then it is assumed that the buffer,
1015.Fa uio
1016is in
1017.Fa "uio->uio_td->td_proc" Ns 's
1018address space.
1019User space memory must be in-core and wired prior to attempting a map
1020load operation.
1021Pages may be locked using
1022.Xr vslock 9 .
1023.It Fn bus_dmamap_unload "dmat" "map"
1024Unloads a DMA map.
1025Arguments are as follows:
1026.Bl -tag -width ".Fa dmam"
1027.It Fa dmat
1028DMA tag used to allocate
1029.Fa map .
1030.It Fa map
1031The DMA map that is to be unloaded.
1032.El
1033.Pp
1034.Fn bus_dmamap_unload
1035will not perform any implicit synchronization of DMA buffers.
1036This must be done explicitly by a call to
1037.Fn bus_dmamap_sync
1038prior to unloading the map.
1039.It Fn bus_dmamap_sync "dmat" "map" "op"
1040Performs synchronization of a device visible mapping with the CPU visible
1041memory referenced by that mapping.
1042Arguments are as follows:
1043.Bl -tag -width ".Fa dmat"
1044.It Fa dmat
1045DMA tag used to allocate
1046.Fa map .
1047.It Fa map
1048The DMA mapping to be synchronized.
1049.It Fa op
1050Type of synchronization operation to perform.
1051See the definition of
1052.Vt bus_dmasync_op_t
1053for a description of the acceptable values for
1054.Fa op .
1055.El
1056.Pp
1057The
1058.Fn bus_dmamap_sync
1059function
1060is the method used to ensure that CPU's and device's direct
1061memory access (DMA) to shared
1062memory is coherent.
1063For example, the CPU might be used to set up the contents of a buffer
1064that is to be made available to a device.
1065To ensure that the data are visible via the device's mapping of that
1066memory, the buffer must be loaded and a DMA sync operation of
1067.Dv BUS_DMASYNC_PREWRITE
1068must be performed after the CPU has updated the buffer and before the device
1069access is initiated.
1070If the CPU modifies this buffer again later, another
1071.Dv BUS_DMASYNC_PREWRITE
1072sync operation must be performed before an additional device
1073access.
1074Conversely, suppose a device updates memory that is to be read by a CPU.
1075In this case, the buffer must be loaded, and a DMA sync operation of
1076.Dv BUS_DMASYNC_PREREAD
1077must be performed before the device access is initiated.
1078The CPU will only be able to see the results of this memory update
1079once the DMA operation has completed and a
1080.Dv BUS_DMASYNC_POSTREAD
1081sync operation has been performed.
1082.Pp
1083If read and write operations are not preceded and followed by the
1084appropriate synchronization operations, behavior is undefined.
1085.It Fn bus_dmamem_alloc "dmat" "**vaddr" "flags" "*mapp"
1086Allocates memory that is mapped into KVA at the address returned
1087in
1088.Fa vaddr
1089and that is permanently loaded into the newly created
1090.Vt bus_dmamap_t
1091returned via
1092.Fa mapp .
1093Arguments are as follows:
1094.Bl -tag -width ".Fa alignment"
1095.It Fa dmat
1096DMA tag describing the constraints of the DMA mapping.
1097.It Fa vaddr
1098Pointer to a pointer that will hold the returned KVA mapping of
1099the allocated region.
1100.It Fa flags
1101Flags are defined as follows:
1102.Bl -tag -width ".Dv BUS_DMA_NOWAIT"
1103.It Dv BUS_DMA_WAITOK
1104The routine can safely wait (sleep) for resources.
1105.It Dv BUS_DMA_NOWAIT
1106The routine is not allowed to wait for resources.
1107If resources are not available,
1108.Dv ENOMEM
1109is returned.
1110.It Dv BUS_DMA_COHERENT
1111Attempt to map this memory in a coherent fashion.
1112See
1113.Fn bus_dmamap_create
1114above for a description of this flag.
1115For
1116.Fn bus_dmamem_alloc ,
1117the
1118.Dv BUS_DMA_COHERENT
1119flag is currently implemented on arm and arm64.
1120.It Dv BUS_DMA_ZERO
1121Causes the allocated memory to be set to all zeros.
1122.It Dv BUS_DMA_NOCACHE
1123The allocated memory will not be cached in the processor caches.
1124All memory accesses appear on the bus and are executed
1125without reordering.
1126For
1127.Fn bus_dmamem_alloc ,
1128the
1129.Dv BUS_DMA_NOCACHE
1130flag is currently implemented on amd64 and i386 where it results in the
1131Strong Uncacheable PAT to be set for the allocated virtual address range.
1132.El
1133.It Fa mapp
1134Pointer to a
1135.Vt bus_dmamap_t
1136where the resulting DMA map will be stored.
1137.El
1138.Pp
1139The size of memory to be allocated is
1140.Fa maxsize
1141as specified in the call to
1142.Fn bus_dma_tag_create
1143for
1144.Fa dmat .
1145.Pp
1146The current implementation of
1147.Fn bus_dmamem_alloc
1148will allocate all requests as a single segment.
1149.Pp
1150An initial load operation is required to obtain the bus address of the allocated
1151memory, and an unload operation is required before freeing the memory, as
1152described below in
1153.Fn bus_dmamem_free .
1154Maps are automatically handled by this function and should not be explicitly
1155allocated or destroyed.
1156.Pp
1157Although an explicit load is not required for each access to the memory
1158referenced by the returned map, the synchronization requirements
1159as described in the
1160.Fn bus_dmamap_sync
1161section still apply and should be used to achieve portability on architectures
1162without coherent buses.
1163.Pp
1164Returns
1165.Er ENOMEM
1166if sufficient memory is not available for completing
1167the operation.
1168.It Fn bus_dmamem_free "dmat" "*vaddr" "map"
1169Frees memory previously allocated by
1170.Fn bus_dmamem_alloc .
1171Any mappings
1172will be invalidated.
1173Arguments are as follows:
1174.Bl -tag -width ".Fa vaddr"
1175.It Fa dmat
1176DMA tag.
1177.It Fa vaddr
1178Kernel virtual address of the memory.
1179.It Fa map
1180DMA map to be invalidated.
1181.El
1182.El
1183.Sh RETURN VALUES
1184Behavior is undefined if invalid arguments are passed to
1185any of the above functions.
1186If sufficient resources cannot be allocated for a given
1187transaction,
1188.Er ENOMEM
1189is returned.
1190All
1191routines that are not of type
1192.Vt void
1193will return 0 on success or an error
1194code on failure as discussed above.
1195.Pp
1196All
1197.Vt void
1198routines will succeed if provided with valid arguments.
1199.Sh LOCKING
1200Two locking protocols are used by
1201.Nm .
1202The first is a private global lock that is used to synchronize access to the
1203bounce buffer pool on the architectures that make use of them.
1204This lock is strictly a leaf lock that is only used internally to
1205.Nm
1206and is not exposed to clients of the API.
1207.Pp
1208The second protocol involves protecting various resources stored in the tag.
1209Since almost all
1210.Nm
1211operations are done through requests from the driver that created the tag,
1212the most efficient way to protect the tag resources is through the lock that
1213the driver uses.
1214In cases where
1215.Nm
1216acts on its own without being called by the driver, the lock primitive
1217specified in the tag is acquired and released automatically.
1218An example of this is when the
1219.Fn bus_dmamap_load
1220callback function is called from a deferred context instead of the driver
1221context.
1222This means that certain
1223.Nm
1224functions must always be called with the same lock held that is specified in the
1225tag.
1226These functions include:
1227.Pp
1228.Bl -item -offset indent -compact
1229.It
1230.Fn bus_dmamap_load
1231.It
1232.Fn bus_dmamap_load_bio
1233.It
1234.Fn bus_dmamap_load_ccb
1235.It
1236.Fn bus_dmamap_load_mbuf
1237.It
1238.Fn bus_dmamap_load_mbuf_sg
1239.It
1240.Fn bus_dmamap_load_uio
1241.It
1242.Fn bus_dmamap_unload
1243.It
1244.Fn bus_dmamap_sync
1245.El
1246.Pp
1247There is one exception to this rule.
1248It is common practice to call some of these functions during driver start-up
1249without any locks held.
1250So long as there is a guarantee of no possible concurrent use of the tag by
1251different threads during this operation, it is safe to not hold a lock for
1252these functions.
1253.Pp
1254Certain
1255.Nm
1256operations should not be called with the driver lock held, either because
1257they are already protected by an internal lock, or because they might sleep
1258due to memory or resource allocation.
1259The following functions must not be
1260called with any non-sleepable locks held:
1261.Pp
1262.Bl -item -offset indent -compact
1263.It
1264.Fn bus_dma_tag_create
1265.It
1266.Fn bus_dmamap_create
1267.It
1268.Fn bus_dmamem_alloc
1269.El
1270.Pp
1271All other functions do not have a locking protocol and can thus be
1272called with or without any system or driver locks held.
1273.Sh SEE ALSO
1274.Xr devclass 9 ,
1275.Xr device 9 ,
1276.Xr driver 9 ,
1277.Xr rman 9 ,
1278.Xr vslock 9
1279.Pp
1280.Rs
1281.%A "Jason R. Thorpe"
1282.%T "A Machine-Independent DMA Framework for NetBSD"
1283.%J "Proceedings of the Summer 1998 USENIX Technical Conference"
1284.%Q "USENIX Association"
1285.%D "June 1998"
1286.Re
1287.Sh HISTORY
1288The
1289.Nm
1290interface first appeared in
1291.Nx 1.3 .
1292.Pp
1293The
1294.Nm
1295API was adopted from
1296.Nx
1297for use in the CAM SCSI subsystem.
1298The alterations to the original API were aimed to remove the need for
1299a
1300.Vt bus_dma_segment_t
1301array stored in each
1302.Vt bus_dmamap_t
1303while allowing callers to queue up on scarce resources.
1304.Sh AUTHORS
1305The
1306.Nm
1307interface was designed and implemented by
1308.An Jason R. Thorpe
1309of the Numerical Aerospace Simulation Facility, NASA Ames Research Center.
1310Additional input on the
1311.Nm
1312design was provided by
1313.An -nosplit
1314.An Chris Demetriou ,
1315.An Charles Hannum ,
1316.An Ross Harvey ,
1317.An Matthew Jacob ,
1318.An Jonathan Stone ,
1319and
1320.An Matt Thomas .
1321.Pp
1322The
1323.Nm
1324interface in
1325.Fx
1326benefits from the contributions of
1327.An Justin T. Gibbs ,
1328.An Peter Wemm ,
1329.An Doug Rabson ,
1330.An Matthew N. Dodd ,
1331.An Sam Leffler ,
1332.An Maxime Henrion ,
1333.An Jake Burkholder ,
1334.An Takahashi Yoshihiro ,
1335.An Scott Long
1336and many others.
1337.Pp
1338This manual page was written by
1339.An Hiten M. Pandya
1340and
1341.An Justin T. Gibbs .
1342