blob: a003831e3f48ae9506270a689ceec40e66f0d6cb [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2016, Google, Inc. All rights reserved
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#pragma once
#include <err.h>
#include <kernel/mutex.h>
#include <list.h>
#include <zircon/types.h>
#include <sys/types.h>
__BEGIN_CDECLS
/**
* The pow2_range_allocator is a small utility library which partitions a set of
* ranges of integers into sub-ranges which are power of 2 in length and power
* of 2 aligned and then manages allocating and freeing the subranges for
* clients. It is responsible for breaking larger sub-regions into smaller ones
* as needed for allocation, and for merging sub-regions into larger sub-regions
* as needed during free operations.
*
* Its primary use is as a utility library for plaforms who need to manage
* allocating blocks MSI IRQ IDs on behalf of the PCI bus driver, but could (in
* theory) be used for other things).
*/
typedef struct p2ra_state {
DECLARE_MUTEX(p2ra_state) lock;
struct list_node ranges;
struct list_node unused_blocks;
struct list_node allocated_blocks;
struct list_node* free_block_buckets;
uint bucket_count;
} p2ra_state_t;
/**
* Initialize the state of a pow2 range allocator.
*
* @param state A pointer to the state structure to be initialized.
* @param max_alloc_size The maximum size of a single contiguous allocation.
* Must be a power of 2.
*
* @return A status code indicating the success or failure of the operation.
*/
zx_status_t p2ra_init(p2ra_state_t* state, uint max_alloc_size);
/**
* Free all of the state associated with a previously initialized pow2 range
* allocator.
*
* @param state A pointer to the state structure to be cleaned up.
*/
void p2ra_free(p2ra_state_t* state);
/**
* Add a range of uints to the pool of ranges to be allocated.
*
* @param state A pointer to the state structure to add the range to.
* @param range_start The start of the uint range.
* @param range_len The length of the uint range.
*
* @return A status code incidcating the success or failure of the operation.
* Possible return values include
* ++ ZX_ERR_INVALID_ARGS range_len is zero, or would cause the range to wrap the
* maximum range of a uint.
* ++ ZX_ERR_ALREADY_EXISTS the specified range overlaps with a range already added
* to the allocator.
* ++ ZX_ERR_NO_MEMORY Not enough memory to allocate the bookkeeping required for
* managing the range.
*/
zx_status_t p2ra_add_range(p2ra_state_t* state, uint range_start, uint range_len);
/**
* Attempt to allocate a range of uints from the available sub-ranges. The
* sizeo the allocated range must be a power of 2, and if the allocation
* succeeds, it is guaranteed to be aligned on a power of 2 boundary matching it
* size.
*
* @param state A pointer to the state structure to allocate from.
* @param size The requested size of the region.
* @param out_range_start An out parameter which will hold the start of the
* allocated range upon success.
*
* @return A status code indicating the success or failure of the operation.
* Possible return values include
* ++ ZX_ERR_INVALID_ARGS Multiple reasons, including...
* ++ size is zero.
* ++ size is not a power of two.
* ++ out_range_start is NULL.
* ++ ZX_ERR_NO_RESOURCES No contiguous, aligned region could be found to satisfy
* the allocation request.
* ++ ZX_ERR_NO_MEMORY A region could be found, but memory required for bookkeeping
* could not be allocated.
*/
zx_status_t p2ra_allocate_range(p2ra_state_t* state, uint size, uint* out_range_start);
/**
* Free a range previously allocated using p2ra_allocate_range.
*
* @param state A pointer to the state structure to return the range to.
* @param range_start The start of the previously allocated range.
* @param size The size of the previously allocated range.
*/
void p2ra_free_range(p2ra_state_t* state, uint range_start, uint size);
__END_CDECLS