#include <drm/ttm/ttm_module.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/drm_mm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/module.h>
struct ttm_range_manager {
struct drm_mm mm;
spinlock_t lock;
};
static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
struct ttm_mem_reg *mem)
{
struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
struct drm_mm *mm = &rman->mm;
struct drm_mm_node *node;
enum drm_mm_insert_mode mode;
unsigned long lpfn;
int ret;
lpfn = place->lpfn;
if (!lpfn)
lpfn = man->size;
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
return -ENOMEM;
mode = DRM_MM_INSERT_BEST;
if (place->flags & TTM_PL_FLAG_TOPDOWN)
mode = DRM_MM_INSERT_HIGH;
lockmgr(&rman->lock, LK_EXCLUSIVE);
ret = drm_mm_insert_node_in_range(mm, node,
mem->num_pages,
mem->page_alignment, 0,
place->fpfn, lpfn, mode);
lockmgr(&rman->lock, LK_RELEASE);
if (unlikely(ret)) {
kfree(node);
} else {
mem->mm_node = node;
mem->start = node->start;
}
return 0;
}
static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
struct ttm_mem_reg *mem)
{
struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
if (mem->mm_node) {
lockmgr(&rman->lock, LK_EXCLUSIVE);
drm_mm_remove_node(mem->mm_node);
lockmgr(&rman->lock, LK_RELEASE);
kfree(mem->mm_node);
mem->mm_node = NULL;
}
}
static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
unsigned long p_size)
{
struct ttm_range_manager *rman;
rman = kzalloc(sizeof(*rman), GFP_KERNEL);
if (!rman)
return -ENOMEM;
drm_mm_init(&rman->mm, 0, p_size);
lockinit(&rman->lock, "ttmrman", 0, 0);
man->priv = rman;
return 0;
}
static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
{
struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
struct drm_mm *mm = &rman->mm;
lockmgr(&rman->lock, LK_EXCLUSIVE);
if (drm_mm_clean(mm)) {
drm_mm_takedown(mm);
lockmgr(&rman->lock, LK_RELEASE);
kfree(rman);
man->priv = NULL;
return 0;
}
lockmgr(&rman->lock, LK_RELEASE);
return -EBUSY;
}
static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
struct drm_printer *printer)
{
struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
lockmgr(&rman->lock, LK_EXCLUSIVE);
drm_mm_print(&rman->mm, printer);
lockmgr(&rman->lock, LK_RELEASE);
}
const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
.init = ttm_bo_man_init,
.takedown = ttm_bo_man_takedown,
.get_node = ttm_bo_man_get_node,
.put_node = ttm_bo_man_put_node,
.debug = ttm_bo_man_debug
};
EXPORT_SYMBOL(ttm_bo_manager_func);