2022-01-18 13:44:59 +03:00
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2021 Intel Corporation
*/
# ifndef __DRM_BUDDY_H__
# define __DRM_BUDDY_H__
# include <linux/bitops.h>
# include <linux/list.h>
# include <linux/slab.h>
# include <linux/sched.h>
# include <drm/drm_print.h>
# define range_overflows(start, size, max) ({ \
typeof ( start ) start__ = ( start ) ; \
typeof ( size ) size__ = ( size ) ; \
typeof ( max ) max__ = ( max ) ; \
( void ) ( & start__ = = & size__ ) ; \
( void ) ( & start__ = = & max__ ) ; \
start__ > = max__ | | size__ > max__ - start__ ; \
} )
2023-09-09 19:09:00 +03:00
# define DRM_BUDDY_RANGE_ALLOCATION BIT(0)
# define DRM_BUDDY_TOPDOWN_ALLOCATION BIT(1)
# define DRM_BUDDY_CONTIGUOUS_ALLOCATION BIT(2)
2022-02-21 19:45:48 +03:00
2022-01-18 13:44:59 +03:00
struct drm_buddy_block {
# define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
# define DRM_BUDDY_HEADER_STATE GENMASK_ULL(11, 10)
# define DRM_BUDDY_ALLOCATED (1 << 10)
# define DRM_BUDDY_FREE (2 << 10)
# define DRM_BUDDY_SPLIT (3 << 10)
/* Free to be used, if needed in the future */
# define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6)
# define DRM_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0)
u64 header ;
struct drm_buddy_block * left ;
struct drm_buddy_block * right ;
struct drm_buddy_block * parent ;
void * private ; /* owned by creator */
/*
* While the block is allocated by the user through drm_buddy_alloc * ,
* the user has ownership of the link , for example to maintain within
* a list , if so desired . As soon as the block is freed with
* drm_buddy_free * ownership is given back to the mm .
*/
struct list_head link ;
struct list_head tmp_link ;
} ;
/* Order-zero must be at least PAGE_SIZE */
# define DRM_BUDDY_MAX_ORDER (63 - PAGE_SHIFT)
/*
* Binary Buddy System .
*
* Locking should be handled by the user , a simple mutex around
* drm_buddy_alloc * and drm_buddy_free * should suffice .
*/
struct drm_buddy {
/* Maintain a free list for each order. */
struct list_head * free_list ;
/*
* Maintain explicit binary tree ( s ) to track the allocation of the
* address space . This gives us a simple way of finding a buddy block
* and performing the potentially recursive merge step when freeing a
* block . Nodes are either allocated or free , in which case they will
* also exist on the respective free list .
*/
struct drm_buddy_block * * roots ;
/*
* Anything from here is public , and remains static for the lifetime of
* the mm . Everything above is considered do - not - touch .
*/
unsigned int n_roots ;
unsigned int max_order ;
/* Must be at least PAGE_SIZE */
u64 chunk_size ;
u64 size ;
u64 avail ;
} ;
static inline u64
drm_buddy_block_offset ( struct drm_buddy_block * block )
{
return block - > header & DRM_BUDDY_HEADER_OFFSET ;
}
static inline unsigned int
drm_buddy_block_order ( struct drm_buddy_block * block )
{
return block - > header & DRM_BUDDY_HEADER_ORDER ;
}
static inline unsigned int
drm_buddy_block_state ( struct drm_buddy_block * block )
{
return block - > header & DRM_BUDDY_HEADER_STATE ;
}
static inline bool
drm_buddy_block_is_allocated ( struct drm_buddy_block * block )
{
return drm_buddy_block_state ( block ) = = DRM_BUDDY_ALLOCATED ;
}
static inline bool
drm_buddy_block_is_free ( struct drm_buddy_block * block )
{
return drm_buddy_block_state ( block ) = = DRM_BUDDY_FREE ;
}
static inline bool
drm_buddy_block_is_split ( struct drm_buddy_block * block )
{
return drm_buddy_block_state ( block ) = = DRM_BUDDY_SPLIT ;
}
static inline u64
drm_buddy_block_size ( struct drm_buddy * mm ,
struct drm_buddy_block * block )
{
return mm - > chunk_size < < drm_buddy_block_order ( block ) ;
}
int drm_buddy_init ( struct drm_buddy * mm , u64 size , u64 chunk_size ) ;
void drm_buddy_fini ( struct drm_buddy * mm ) ;
2022-02-22 20:48:41 +03:00
struct drm_buddy_block *
drm_get_buddy ( struct drm_buddy_block * block ) ;
2022-02-21 19:45:48 +03:00
int drm_buddy_alloc_blocks ( struct drm_buddy * mm ,
u64 start , u64 end , u64 size ,
u64 min_page_size ,
struct list_head * blocks ,
unsigned long flags ) ;
2022-01-18 13:44:59 +03:00
2022-02-21 19:45:50 +03:00
int drm_buddy_block_trim ( struct drm_buddy * mm ,
u64 new_size ,
struct list_head * blocks ) ;
2022-01-18 13:44:59 +03:00
void drm_buddy_free_block ( struct drm_buddy * mm , struct drm_buddy_block * block ) ;
void drm_buddy_free_list ( struct drm_buddy * mm , struct list_head * objects ) ;
void drm_buddy_print ( struct drm_buddy * mm , struct drm_printer * p ) ;
void drm_buddy_block_print ( struct drm_buddy * mm ,
struct drm_buddy_block * block ,
struct drm_printer * p ) ;
# endif