freebsd-skq/sys/sys/busdma_bufalloc.h
cognet 5780ffa994 Create an architecture-agnostic buffer pool manager that uses uma(9) to
manage a set of power-of-2 sized buffers for bus_dmamem_alloc().

This allows the caller to provide the back-end allocator uma allocator,
allowing full control of the memory pages backing the pool.  For
convenience, it provides an optional builtin allocator that provides pages
allocated with the VM_MEMATTR_UNCACHEABLE attribute, for managing pools of
DMA buffers for BUS_DMA_COHERENT or BUS_DMA_NOCACHE.

This also allows the caller to specify a minimum alignment, and it ensures
that all buffers start on a boundary and have a length that's a multiple of
that value, to avoid using buffers that trigger partial cache line flushes.

Submitted by:	Ian Lepore <freebsd@damnhippie.dyndns.org>
2012-12-20 00:34:54 +00:00

119 lines
4.6 KiB
C

/*-
* Copyright (c) 2012 Ian Lepore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $FreeBSD$
*/
/*
* A buffer pool manager, for use by a platform's busdma implementation.
*/
#ifndef _MACHINE_BUSDMA_BUFALLOC_H_
#define _MACHINE_BUSDMA_BUFALLOC_H_
#include <machine/bus.h>
#include <vm/uma.h>
/*
* Information about a buffer zone, returned by busdma_bufalloc_findzone().
*/
struct busdma_bufzone {
bus_size_t size;
uma_zone_t umazone;
char name[24];
};
/*
* Opaque handle type returned by busdma_bufalloc_create().
*/
struct busdma_bufalloc;
typedef struct busdma_bufalloc *busdma_bufalloc_t;
/*
* Create an allocator that manages a pool of DMA buffers.
*
* The allocator manages a collection of uma(9) zones of buffers in power-of-two
* sized increments ranging from minimum_alignment to the platform's PAGE_SIZE.
* The buffers within each zone are aligned on boundaries corresponding to the
* buffer size, and thus by implication each buffer is contiguous within a page
* and does not cross a power of two boundary larger than the buffer size.
* These rules are intended to make it easy for a busdma implementation to
* check whether a tag's constraints allow use of a buffer from the allocator.
*
* minimum_alignment is also the minimum buffer allocation size. For platforms
* with software-assisted cache coherency, this is typically the data cache line
* size (and MUST not be smaller than the cache line size).
*
* name appears in zone stats as 'dma name nnnnn' where 'dma' is fixed and
* 'nnnnn' is the size of buffers in that zone.
*
* If if the alloc/free function pointers are NULL, the regular uma internal
* allocators are used (I.E., you get "plain old kernel memory"). On a platform
* with an exclusion zone that applies to all DMA operations, a custom allocator
* could be used to ensure no buffer memory is ever allocated from that zone,
* allowing the bus_dmamem_alloc() implementation to make the assumption that
* buffers provided by the allocation could never lead to the need for a bounce.
*/
busdma_bufalloc_t busdma_bufalloc_create(const char *name,
bus_size_t minimum_alignment,
uma_alloc uma_alloc_func, uma_free uma_free_func,
u_int32_t uma_zcreate_flags);
/*
* Destroy an allocator created by busdma_bufalloc_create().
* Safe to call with a NULL pointer.
*/
void busdma_bufalloc_destroy(busdma_bufalloc_t ba);
/*
* Return a pointer to the busdma_bufzone that should be used to allocate or
* free a buffer of the given size. Returns NULL if the size is larger than the
* largest zone handled by the allocator.
*/
struct busdma_bufzone * busdma_bufalloc_findzone(busdma_bufalloc_t ba,
bus_size_t size);
/*
* These built-in allocation routines are available for managing a pools of
* uncacheable memory on platforms that support VM_MEMATTR_UNCACHEABLE.
*
* Allocation is done using kmem_alloc_attr() with these parameters:
* lowaddr = 0
* highaddr = BUS_SPACE_MAXADDR
* memattr = VM_MEMATTR_UNCACHEABLE.
*
* If your platform has no exclusion region (lowaddr/highaddr), and its pmap
* routines support pmap_page_set_memattr() and the VM_MEMATTR_UNCACHEABLE flag
* you can probably use these when you need uncacheable buffers.
*/
void * busdma_bufalloc_alloc_uncacheable(uma_zone_t zone, int size,
u_int8_t *pflag, int wait);
void busdma_bufalloc_free_uncacheable(void *item, int size, u_int8_t pflag);
#endif /* _MACHINE_BUSDMA_BUFALLOC_H_ */