/**
 * \file
 *
 * \brief DMA memory pool allocator
 *
 * This file is just a wrapper around the CPU-specific DMA pool
 * header.
 *
 * \sa mempool.h
 *
 * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32
 * - Supported devices:  All devices
 * - AppNote:
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support and FAQ: http://support.atmel.no/
 *
 * \page License
 *
 * 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.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 * Atmel AVR product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
 */
#ifndef DMAPOOL_H_INCLUDED
#define DMAPOOL_H_INCLUDED

#include <cpu/dmapool.h>

void dma_pool_init_coherent_physmem(struct dma_pool *dmapool,
		struct physmem_pool *phys_pool, unsigned int nr_objects,
		size_t objsize, unsigned int align_order);

#ifdef CONFIG_DMAPOOL_GENERIC_POOLS
#include <assert.h>
#include <app/config_dmapool.h>

#ifdef CONFIG_DMAPOOL_SMALL_OBJ_SIZE
extern struct dma_pool dmapool_size_small;
#endif
#ifdef CONFIG_DMAPOOL_LARGE_OBJ_SIZE
extern struct dma_pool dmapool_size_large;
#endif

static inline struct dma_pool *dmapool_find_pool(size_t alloc_size)
{
#ifdef CONFIG_DMAPOOL_SMALL_OBJ_SIZE
	if (alloc_size <= CONFIG_DMAPOOL_SMALL_OBJ_SIZE)
		return &dmapool_size_small;
#endif
#ifdef CONFIG_DMAPOOL_LARGE_OBJ_SIZE
	if (alloc_size <= CONFIG_DMAPOOL_LARGE_OBJ_SIZE)
		return &dmapool_size_large;
#endif

	return NULL;
}

static inline void *dma_alloc_inline(phys_addr_t *paddr, size_t size)
{
	struct dma_pool	*pool;

	pool = dmapool_find_pool(size);
	if (likely(pool))
		return dma_pool_alloc(pool, paddr);
	else
		return NULL;
}

extern void *dma_alloc_noninline(phys_addr_t *paddr, size_t size);

/**
 * \brief Allocate an object from the generic DMA pools
 *
 * This function picks the smallest generic DMA pool which can hold
 * objects of size less than or equal to \a size and allocates an
 * object from it.
 *
 * \param paddr Pointer to where the physical address of the object is
 *	to be stored.
 * \param size Minimum size of the object to allocate
 *
 * \return A pointer to an object of at least \a size bytes, or NULL
 * if the selected DMA pool is exhausted.
 */
static inline void *dma_alloc(phys_addr_t *paddr, size_t size)
{
	if (is_constant(size))
		return dma_alloc_inline(paddr, size);
	else
		return dma_alloc_noninline(paddr, size);
}

static inline void dma_free_inline(const void *obj, size_t size)
{
	struct dma_pool	*pool;

	pool = dmapool_find_pool(size);
	assert(pool);
	dma_pool_free(pool, obj);
}

extern void dma_free_noninline(const void *obj, size_t size);

/**
 * \brief Free an object to the generic DMA pools
 *
 * This function picks the same generic DMA pool picked based on \a
 * size, and frees the object to it.
 *
 * \param obj The object to be freed.
 * \param size The minimum size of the object. Must be the same value
 * as was passed to dma_alloc() when this object was returned.
 */
static inline void dma_free(const void *obj, size_t size)
{
	if (is_constant(size))
		dma_free_inline(obj, size);
	else
		dma_free_noninline(obj, size);
}

extern void dma_pool_init(void);

#endif /* CONFIG_DMAPOOL_GENERIC_POOLS */

#endif /* DMAPOOL_H_INCLUDED */
