Files
linux-nvgpu/drivers/gpu/nvgpu/gk20a/gk20a_allocator.h
Alex Waterman ba2014d367 gpu: nvgpu: Implement a bitmap allocator
Implement a bitmap allocator for GPU use. This allocator is useful for
managing memory (or resource) regions where the buddy allocator is not
ideal. Some instances are small regions or where the resource management
must not make calls to the kernel's memory allocation routines (anything
that ultimately calls alloc_page()).

The code path where this avoidance of alloc_page() is most required is
the gpfifo submit path. In order to keep this routine fast and have
predicable time constraints no alloc_page() calls is necessary. The
buddy allocator does not work for this since every time a buddy is
allocated there is the possibility that a pair (or more) buddy structs
have to be made. These allocs could perhaps require a call into
alloc_page() if there is not enouch space in the kmem_cache slab for
the buddy structs.

Change-Id: Ia46fce62d4bdafcebbc153b21b515cb51641d241
Signed-off-by: Alex Waterman <alexw@nvidia.com>
Reviewed-on: http://git-master/r/1176446
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
2016-07-19 11:32:38 -07:00

222 lines
6.5 KiB
C

/*
* Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GK20A_ALLOCATOR_H
#define GK20A_ALLOCATOR_H
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/platform_device.h>
/* #define ALLOCATOR_DEBUG */
struct gk20a_allocator;
struct vm_gk20a;
/*
* Operations for an allocator to implement.
*/
struct gk20a_allocator_ops {
u64 (*alloc)(struct gk20a_allocator *allocator, u64 len);
void (*free)(struct gk20a_allocator *allocator, u64 addr);
/*
* Special interface to allocate a memory region with a specific
* starting address. Yikes. Note: if free() works for freeing both
* regular and fixed allocations then free_fixed() does not need to
* be implemented. This behavior exists for legacy reasons and should
* not be propagated to new allocators.
*/
u64 (*alloc_fixed)(struct gk20a_allocator *allocator,
u64 base, u64 len);
void (*free_fixed)(struct gk20a_allocator *allocator,
u64 base, u64 len);
/*
* Returns info about the allocator.
*/
u64 (*base)(struct gk20a_allocator *allocator);
u64 (*length)(struct gk20a_allocator *allocator);
u64 (*end)(struct gk20a_allocator *allocator);
int (*inited)(struct gk20a_allocator *allocator);
/* Destructor. */
void (*fini)(struct gk20a_allocator *allocator);
/* Debugging. */
void (*print_stats)(struct gk20a_allocator *allocator,
struct seq_file *s, int lock);
};
struct gk20a_allocator {
char name[32];
struct mutex lock;
void *priv;
const struct gk20a_allocator_ops *ops;
struct dentry *debugfs_entry;
bool debug; /* Control for debug msgs. */
};
/*
* These are the available allocator flags.
*
* GPU_ALLOC_GVA_SPACE
*
* This flag makes sense for the buddy allocator only. It specifies that the
* allocator will be used for managing a GVA space. When managing GVA spaces
* special care has to be taken to ensure that allocations of similar PTE
* sizes are placed in the same PDE block. This allows the higher level
* code to skip defining both small and large PTE tables for every PDE. That
* can save considerable memory for address spaces that have a lot of
* allocations.
*
* GPU_ALLOC_NO_ALLOC_PAGE
*
* For any allocator that needs to manage a resource in a latency critical
* path this flag specifies that the allocator should not use any kmalloc()
* or similar functions during normal operation. Initialization routines
* may still use kmalloc(). This prevents the possibility of long waits for
* pages when using alloc_page(). Currently only the bitmap allocator
* implements this functionality.
*
* Also note that if you accept this flag then you must also define the
* free_fixed() function. Since no meta-data is allocated to help free
* allocations you need to keep track of the meta-data yourself (in this
* case the base and length of the allocation as opposed to just the base
* of the allocation).
*/
#define GPU_ALLOC_GVA_SPACE 0x1
#define GPU_ALLOC_NO_ALLOC_PAGE 0x2
static inline void alloc_lock(struct gk20a_allocator *a)
{
mutex_lock(&a->lock);
}
static inline void alloc_unlock(struct gk20a_allocator *a)
{
mutex_unlock(&a->lock);
}
/*
* Buddy allocator specific initializers.
*/
int __gk20a_buddy_allocator_init(struct gk20a_allocator *a,
struct vm_gk20a *vm, const char *name,
u64 base, u64 size, u64 blk_size,
u64 max_order, u64 flags);
int gk20a_buddy_allocator_init(struct gk20a_allocator *allocator,
const char *name, u64 base, u64 size,
u64 blk_size, u64 flags);
/*
* Bitmap initializers.
*/
int gk20a_bitmap_allocator_init(struct gk20a_allocator *__a,
const char *name, u64 base, u64 length,
u64 blk_size, u64 flags);
#define GPU_BALLOC_MAX_ORDER 31
/*
* Allocator APIs.
*/
u64 gk20a_alloc(struct gk20a_allocator *allocator, u64 len);
void gk20a_free(struct gk20a_allocator *allocator, u64 addr);
u64 gk20a_alloc_fixed(struct gk20a_allocator *allocator, u64 base, u64 len);
void gk20a_free_fixed(struct gk20a_allocator *allocator, u64 base, u64 len);
u64 gk20a_alloc_base(struct gk20a_allocator *a);
u64 gk20a_alloc_length(struct gk20a_allocator *a);
u64 gk20a_alloc_end(struct gk20a_allocator *a);
u64 gk20a_alloc_initialized(struct gk20a_allocator *a);
void gk20a_alloc_destroy(struct gk20a_allocator *allocator);
void gk20a_alloc_print_stats(struct gk20a_allocator *a,
struct seq_file *s, int lock);
/*
* Common functionality for the internals of the allocators.
*/
void gk20a_init_alloc_debug(struct gk20a_allocator *a);
void gk20a_fini_alloc_debug(struct gk20a_allocator *a);
int __gk20a_alloc_common_init(struct gk20a_allocator *a,
const char *name, void *priv, bool dbg,
const struct gk20a_allocator_ops *ops);
static inline void gk20a_alloc_enable_dbg(struct gk20a_allocator *a)
{
a->debug = true;
}
static inline void gk20a_alloc_disable_dbg(struct gk20a_allocator *a)
{
a->debug = false;
}
/*
* Debug stuff.
*/
extern u32 gk20a_alloc_tracing_on;
void gk20a_alloc_debugfs_init(struct platform_device *pdev);
#define gk20a_alloc_trace_func() \
do { \
if (gk20a_alloc_tracing_on) \
trace_printk("%s\n", __func__); \
} while (0)
#define gk20a_alloc_trace_func_done() \
do { \
if (gk20a_alloc_tracing_on) \
trace_printk("%s_done\n", __func__); \
} while (0)
#define __alloc_pstat(seq, allocator, fmt, arg...) \
do { \
if (s) \
seq_printf(seq, fmt, ##arg); \
else \
alloc_dbg(allocator, fmt, ##arg); \
} while (0)
#define __alloc_dbg(a, fmt, arg...) \
pr_info("%-25s %25s() " fmt, (a)->name, __func__, ##arg)
#if defined(ALLOCATOR_DEBUG)
/*
* Always print the debug messages...
*/
#define alloc_dbg(a, fmt, arg...) __alloc_dbg(a, fmt, ##arg)
#else
/*
* Only print debug messages if debug is enabled for a given allocator.
*/
#define alloc_dbg(a, fmt, arg...) \
do { \
if ((a)->debug) \
__alloc_dbg((a), fmt, ##arg); \
} while (0)
#endif
#endif /* GK20A_ALLOCATOR_H */