/*
*/
/**************************************************************************
*
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
* Copyright (c) 2009, 2013, Intel Corporation.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
**************************************************************************/
/*
* Generic simple memory manager implementation. Intended to be used as a base
* class implementation for more advanced memory managers.
*
* Note that the algorithm used is quite simple and there might be substantial
* performance gains if a smarter free list is implemented. Currently it is just an
* unordered stack of free regions. This could easily be improved if an RB-tree
* is used instead. At least if we expect heavy fragmentation.
*
* Aligned allocations can also see improvement.
*
* Authors:
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
#include "drm_mm.h"
{
if (atomic)
else
else {
child =
struct drm_mm_node, node_list);
--mm->num_unused;
}
}
return child;
}
/* drm_mm_pre_get() - pre allocate drm_mm_node structure
* drm_mm: memory manager struct we are pre-allocating for
*
* Returns 0 on success or -ENOMEM if allocation fails.
*/
{
return ret;
}
++mm->num_unused;
}
return 0;
}
struct drm_mm_node *node,
unsigned long color)
{
if (mm->color_adjust)
if (alignment) {
if (tmp)
}
if (adj_start == hole_start) {
hole_node->hole_follows = 0;
}
node->hole_follows = 0;
}
}
unsigned long start,
unsigned long size,
bool atomic)
{
unsigned long hole_start;
unsigned long hole_end;
continue;
return NULL;
if (start == hole_start) {
hole->hole_follows = 0;
}
node->hole_follows = 0;
}
return node;
}
return NULL;
}
unsigned long size,
unsigned alignment,
unsigned long color,
int atomic)
{
return NULL;
return node;
}
/**
* Search for free space and insert a preallocated memory node. Returns
* -ENOSPC if no suitable free area is available. The preallocated memory node
* must be cleared.
*/
unsigned long color)
{
color, 0);
if (!hole_node)
return -ENOSPC;
return 0;
}
{
}
struct drm_mm_node *node,
unsigned long color,
{
if (mm->color_adjust)
if (alignment) {
if (tmp)
}
if (adj_start == hole_start) {
hole_node->hole_follows = 0;
}
node->hole_follows = 0;
}
}
unsigned long size,
unsigned alignment,
unsigned long color,
unsigned long start,
unsigned long end,
int atomic)
{
return NULL;
return node;
}
/**
* Search for free space and insert a preallocated memory node. Returns
* -ENOSPC if no suitable free area is available. This is for range
* restricted allocations. The preallocated memory node must be cleared.
*/
{
if (!hole_node)
return -ENOSPC;
return 0;
}
{
}
/**
* Remove a memory node from the allocator.
*/
{
|| node->scanned_next_free);
if (node->hole_follows) {
/* LINTED */
} else
if (!prev_node->hole_follows) {
} else
}
/*
* Remove a memory node from the allocator and free the allocated struct
* drm_mm_node. Only to be used on a struct drm_mm_node obtained by one of the
* drm_mm_get_block functions.
*/
{
++mm->num_unused;
} else
}
{
return 0;
if (alignment) {
if (tmp)
}
}
unsigned long size,
unsigned alignment,
unsigned long color,
bool best_match)
{
unsigned long adj_start;
unsigned long adj_end;
unsigned long best_size;
if (mm->color_adjust) {
continue;
}
continue;
if (!best_match)
return entry;
}
}
return best;
}
unsigned long size,
unsigned alignment,
unsigned long color,
unsigned long start,
unsigned long end,
bool best_match)
{
unsigned long adj_start;
unsigned long adj_end;
unsigned long best_size;
if (mm->color_adjust) {
continue;
}
continue;
if (!best_match)
return entry;
}
}
return best;
}
/**
* Moves an allocation. To be used with embedded struct drm_mm_node.
*/
{
}
/**
* Initializa lru scanning.
*
* This simply sets up the scanning routines with the parameters for the desired
* hole.
*
* Warning: As long as the scan list is non-empty, no other operations than
*/
unsigned long size,
unsigned alignment,
unsigned long color)
{
mm->scanned_blocks = 0;
mm->scan_hit_start = 0;
mm->scan_hit_end = 0;
mm->scan_check_range = 0;
}
/**
* Initializa lru scanning.
*
* This simply sets up the scanning routines with the parameters for the desired
* hole. This version is for range-restricted scans.
*
* Warning: As long as the scan list is non-empty, no other operations than
*/
unsigned long size,
unsigned alignment,
unsigned long color,
unsigned long start,
unsigned long end)
{
mm->scanned_blocks = 0;
mm->scan_hit_start = 0;
mm->scan_hit_end = 0;
}
/**
* Add a node to the scan list that might be freed to make space for the desired
* hole.
*
* Returns non-zero, if a hole has been found, zero otherwise.
*/
{
mm->scanned_blocks++;
if (mm->scan_check_range) {
}
if (mm->color_adjust)
return 1;
}
return 0;
}
/**
* Remove a node from the scan list.
*
* Nodes _must_ be removed in the exact same order from the scan list as they
* have been added, otherwise the internal state of the memory manager will be
* corrupted.
*
* When the scan list is empty, the selected memory nodes can be freed. An
* immediatly following drm_mm_search_free with best_match = 0 will then return
* the just freed block (because its at the top of the free_stack list).
*
* Returns one if this block should be evicted, zero otherwise. Will always
* return zero when no hole has been found.
*/
{
mm->scanned_blocks--;
node->scanned_block = 0;
}
{
}
{
mm->num_unused = 0;
mm->scanned_blocks = 0;
/* Clever trick to avoid a special case in the free hole tracking. */
}
{
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return;
}
--mm->num_unused;
}
}
const char *prefix)
{
if (entry->hole_follows) {
DRM_DEBUG("%s 0x%08lx-0x%08lx: %8lu: free\n",
return hole_size;
}
return 0;
}
{
DRM_DEBUG("%s 0x%08lx-0x%08lx: %8lu: used\n",
}
}
{
}
{
}
{
return __drm_mm_hole_node_start(hole_node);
}
{
struct drm_mm_node, node_list);
}
{
return __drm_mm_hole_node_end(hole_node);
}
unsigned long size,
unsigned alignment)
{
}
unsigned long size,
unsigned alignment)
{
}
struct drm_mm_node *parent,
unsigned long size,
unsigned alignment,
unsigned long start,
unsigned long end)
{
}
struct drm_mm_node *parent,
unsigned long size,
unsigned alignment,
unsigned long start,
unsigned long end)
{
}
unsigned long size,
unsigned alignment,
bool best_match)
{
}
unsigned long size,
unsigned alignment,
unsigned long start,
unsigned long end,
bool best_match)
{
}