* Renamed memmgr.c|h to memory_manager.c|h.

* The functions now check the acquire_sem() result.
* mem_freetag() will return an status code now, too.
* Moved the mem_block and mem_info definitions into the source file; no
  reason to have them public.
* You can now give the memory manager a name which it will use for its
  heap area and lock.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17221 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-04-24 15:09:46 +00:00
parent 771b07b64c
commit 9095e05d8d
8 changed files with 375 additions and 356 deletions
-44
View File
@@ -1,44 +0,0 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon kernel driver
Memory manager used for graphics mem
*/
#ifndef _MEMMGR_H
#define _MEMMGR_H
#include <OS.h>
// allocated memory block
typedef struct mem_block {
struct mem_block *prev, *next;
uint32 base;
uint32 size;
void *tag;
bool alloced;
} mem_block;
// memory heap
typedef struct mem_info {
mem_block *first;
area_id heap_area;
uint32 block_size;
sem_id lock;
mem_block *heap;
mem_block *unused;
uint32 heap_entries;
} mem_info;
mem_info *mem_init( uint32 start, uint32 len, uint32 block_size, uint32 heap_entries );
void mem_destroy( mem_info *mem );
status_t mem_alloc( mem_info *mem, uint32 size, void *tag, uint32 *block, uint32 *offset );
status_t mem_free( mem_info *mem, uint32 block_id, void *tag );
void mem_freetag( mem_info *mem, void *tag );
#endif
@@ -0,0 +1,32 @@
/*
* Copyright 2006, Haiku Inc.
* Copyright 2002, Thomas Kurschel.
*
* Distributed under the terms of the MIT license.
*/
#ifndef _MEMORY_MANAGER_H
#define _MEMORY_MANAGER_H
/** Memory manager used for graphics mem */
#include <OS.h>
typedef struct mem_info mem_info;
#ifdef __cplusplus
extern "C" {
#endif
mem_info *mem_init(const char *name, uint32 start, uint32 length, uint32 blockSize,
uint32 heapEntries);
void mem_destroy(mem_info *mem);
status_t mem_alloc(mem_info *mem, uint32 size, void *tag, uint32 *blockID, uint32 *offset);
status_t mem_free(mem_info *mem, uint32 blockID, void *tag);
status_t mem_freetag(mem_info *mem, void *tag);
#ifdef __cplusplus
}
#endif
#endif /* _MEMORY_MANAGER_H */
@@ -9,5 +9,5 @@ UsePrivateHeaders [ FDirName graphics common ] ;
StaticLibrary libgraphicscommon.a :
log_coll.c
log_dump.c
memmgr.c
memory_manager.c
;
@@ -1,282 +0,0 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon kernel driver
Memory manager used for graphics mem
It has the following features
- doesn't access memory to be managed
- memory block's owner is identified by tag,
tag is verified during free, and all memory
belonging to one tag can be freed at once
- multi-threading save
*/
#include "memmgr.h"
#include <malloc.h>
#include "KernelExport.h"
#define debug_level_flow 4
#define debug_level_info 4
#define debug_level_error 4
#define DEBUG_MSG_PREFIX "Graphics Driver - "
#include "debug_ext.h"
#if 0
#ifndef _KERNEL_MODE
void _kdprintf_(const char *format, ...);
//bool set_dprintf_enabled(bool); /* returns old enable flag */
#define dprintf _kdprintf_
#endif
#endif
// init manager
// start - start of address space
// len - len of address space
// block_size - granularity
// heap_entries - maximum number of blocks
mem_info *mem_init( uint32 start, uint32 len, uint32 block_size, uint32 heap_entries )
{
mem_block *first;
mem_info *mem;
uint i;
uint32 size;
SHOW_FLOW( 2, "start=%lx, len=%lx, block_size=%lx, heap_entries=%ld",
start, len, block_size, heap_entries );
mem = malloc( sizeof( *mem ));
if( mem == NULL )
goto err;
mem->block_size = block_size;
mem->heap_entries = heap_entries;
mem->lock = create_sem( 1, "mem_lock" );
if( mem->lock < 0 )
goto err2;
// align size to B_PAGE_SIZE
size = heap_entries * sizeof(mem_block);
if ((size / B_PAGE_SIZE) * B_PAGE_SIZE != size)
size = ((size / B_PAGE_SIZE) + 1) * B_PAGE_SIZE;
mem->heap_area = create_area("memmgr_heap_area", (void **)&mem->heap,
B_ANY_ADDRESS, size, B_FULL_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (mem->heap_area < 0 || mem->heap == NULL)
goto err3;
for( i = 1; i < heap_entries; ++i )
mem->heap[i-1].next = &mem->heap[i];
mem->heap[heap_entries - 1].next = NULL;
mem->unused = &mem->heap[1];
first = &mem->heap[0];
mem->first = first;
first->base = start;
first->size = len;
first->prev = first->next = NULL;
first->alloced = false;
return mem;
err3:
delete_sem( mem->lock );
err2:
free( mem );
err:
return NULL;
}
// destroy heap
void mem_destroy( mem_info *mem )
{
SHOW_FLOW0( 2, "" );
delete_area(mem->heap_area);
delete_sem(mem->lock);
free(mem);
}
// allocate memory block
// in:
// mem - heap handle
// size - size in bytes
// tag - owner tag
// out:
// block_id - block id
// offset - start address of block
status_t mem_alloc( mem_info *mem, uint32 size, void *tag, uint32 *block_id, uint32 *offset )
{
mem_block *cur, *new_entry;
SHOW_FLOW( 2, "size=%ld, tag=%p", size, tag );
acquire_sem( mem->lock );
// we assume block_size is power of two
size = (size + mem->block_size - 1) & ~(mem->block_size - 1);
// simple first fit
for( cur = mem->first; cur; cur = cur->next ) {
if( !cur->alloced && cur->size >= size )
break;
}
if( cur == NULL ) {
SHOW_FLOW0( 2, "out of memory" );
goto err;
}
if( size != cur->size ) {
new_entry = mem->unused;
if( new_entry == NULL ) {
SHOW_FLOW0( 2, "out of blocks" );
goto err;
}
mem->unused = new_entry->next;
new_entry->next = cur->next;
new_entry->prev = cur;
new_entry->alloced = false;
new_entry->base = cur->base + size;
new_entry->size = cur->size - size;
if( cur->next )
cur->next->prev = new_entry;
cur->next = new_entry;
cur->size = size;
}
cur->alloced = true;
cur->tag = tag;
*block_id = cur - mem->heap + 1;
*offset = cur->base;
release_sem( mem->lock );
SHOW_FLOW( 2, "block_id=%ld, offset=%lx", *block_id, *offset );
return B_OK;
err:
release_sem( mem->lock );
return B_NO_MEMORY;
}
// merge "block" with successor
static void merge( mem_info *mem, mem_block *block )
{
mem_block *next;
next = block->next;
block->size += next->size;
if( next->next )
next->next->prev = block;
block->next = next->next;
next->next = mem->unused;
mem->unused = next;
}
// internal: free memory block including merge
static mem_block *freeblock( mem_info *mem, mem_block *block )
{
mem_block *prev, *next;
block->alloced = false;
prev = block->prev;
if( prev && !prev->alloced ) {
block = prev;
merge( mem, prev );
}
next = block->next;
if( next && !next->alloced )
merge( mem, block );
return block;
}
// free memory
// mem - heap handle
// block_id - block id
// tag - owner tag (must match tag passed to mem_alloc)
status_t mem_free( mem_info *mem, uint32 block_id, void *tag )
{
mem_block *block;
SHOW_FLOW( 2, "block_id=%ld, tag=%p", block_id, tag );
acquire_sem( mem->lock );
--block_id;
if( block_id >= mem->heap_entries ) {
SHOW_ERROR0( 2, "invalid id" );
goto err;
}
block = &mem->heap[block_id];
if( !block->alloced || block->tag != tag ) {
SHOW_ERROR0( 2, "not owner" );
goto err;
}
freeblock( mem, block );
release_sem( mem->lock );
SHOW_FLOW0( 2, "success" );
return B_OK;
err:
release_sem( mem->lock );
return B_BAD_VALUE;
}
// free all memory belonging to owner "tag"
void mem_freetag( mem_info *mem, void *tag )
{
mem_block *cur;
SHOW_FLOW( 2, "tag=%p", tag );
acquire_sem( mem->lock );
for( cur = mem->first; cur; cur = cur->next ) {
if( cur->alloced && cur->tag == tag )
cur = freeblock( mem, cur );
}
release_sem( mem->lock );
SHOW_FLOW0( 2, "done" );
}
@@ -0,0 +1,316 @@
/*
* Copyright 2006, Haiku Inc.
* Copyright 2002, Thomas Kurschel.
*
* Distributed under the terms of the MIT license.
*/
/** Memory manager used for graphics mem
*
* It has the following features
* - doesn't access memory to be managed
* - memory block's owner is identified by tag,
* tag is verified during free, and all memory
* belonging to one tag can be freed at once
* - multi-threading save
*/
#include "memory_manager.h"
#include <KernelExport.h>
#include <stdlib.h>
//#define TRACE_MEMORY_MANAGER
#ifdef TRACE_MEMORY_MANAGER
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
// allocated memory block
typedef struct mem_block {
struct mem_block *prev, *next;
uint32 base;
uint32 size;
void *tag;
bool allocated;
} mem_block;
// memory heap
struct mem_info {
mem_block *first;
area_id heap_area;
uint32 block_size;
sem_id lock;
mem_block *heap;
mem_block *unused;
uint32 heap_entries;
};
/** merge "block" with successor */
static void
merge(mem_info *mem, mem_block *block)
{
mem_block *next = block->next;
block->size += next->size;
if (next->next)
next->next->prev = block;
block->next = next->next;
next->next = mem->unused;
mem->unused = next;
}
/** free memory block including merge */
static mem_block *
freeblock(mem_info *mem, mem_block *block)
{
mem_block *prev, *next;
block->allocated = false;
prev = block->prev;
if (prev && !prev->allocated) {
block = prev;
merge(mem, prev);
}
next = block->next;
if (next && !next->allocated)
merge(mem, block);
return block;
}
// #pragma mark -
/** Init memory manager.
*
* \param start start of address space
* \param length length of address space
* \param blockSize - granularity
* \param heapEntries - maximum number of blocks
*/
mem_info *
mem_init(const char* name, uint32 start, uint32 length,
uint32 blockSize, uint32 heapEntries)
{
mem_block *first;
mem_info *mem;
uint i;
uint32 size;
TRACE(("mem_init(name=%s, start=%lx, length=%lx, blockSize=%lx, heapEntries=%ld)\n",
name, start, length, blockSize, heapEntries));
mem = malloc(sizeof(*mem));
if (mem == NULL)
goto err1;
mem->block_size = blockSize;
mem->heap_entries = heapEntries;
mem->lock = create_sem(1, name);
if (mem->lock < 0)
goto err2;
// align size to B_PAGE_SIZE
size = heapEntries * sizeof(mem_block);
size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
mem->heap_area = create_area(name, (void **)&mem->heap,
B_ANY_ADDRESS, size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
if (mem->heap_area < 0 || mem->heap == NULL)
goto err3;
for (i = 1; i < heapEntries; ++i) {
mem->heap[i - 1].next = &mem->heap[i];
}
mem->heap[heapEntries - 1].next = NULL;
mem->unused = &mem->heap[1];
first = &mem->heap[0];
mem->first = first;
first->base = start;
first->size = length;
first->prev = first->next = NULL;
first->allocated = false;
return mem;
err3:
delete_sem(mem->lock);
err2:
free(mem);
err1:
return NULL;
}
/** destroy heap */
void
mem_destroy(mem_info *mem)
{
TRACE(("mem_destroy(mem %p)\n", mem));
delete_area(mem->heap_area);
delete_sem(mem->lock);
free(mem);
}
/** Allocate memory block
*
* \param mem heap handle
* \param size size in bytes
* \param tag owner tag
*
* \param blockID - returns block id
* \param offset - returns start address of block
*/
status_t
mem_alloc(mem_info *mem, uint32 size, void *tag, uint32 *blockID, uint32 *offset)
{
mem_block *current, *newEntry;
status_t status;
TRACE(("mem_alloc(mem %p, size=%ld, tag=%p", mem, size, tag));
status = acquire_sem(mem->lock);
if (status != B_OK)
return status;
// we assume block_size is power of two
size = (size + mem->block_size - 1) & ~(mem->block_size - 1);
// simple first fit
for (current = mem->first; current; current = current->next) {
if (!current->allocated && current->size >= size)
break;
}
if (current == NULL) {
TRACE(("mem_alloc: out of memory\n"));
goto err;
}
if (size != current->size) {
newEntry = mem->unused;
if (newEntry == NULL) {
TRACE(("mem_alloc: out of blocks\n"));
goto err;
}
mem->unused = newEntry->next;
newEntry->next = current->next;
newEntry->prev = current;
newEntry->allocated = false;
newEntry->base = current->base + size;
newEntry->size = current->size - size;
if (current->next)
current->next->prev = newEntry;
current->next = newEntry;
current->size = size;
}
current->allocated = true;
current->tag = tag;
*blockID = current - mem->heap + 1;
*offset = current->base;
release_sem(mem->lock);
TRACE(("mem_alloc(block_id=%ld, offset=%lx)\n", *blockID, *offset));
return B_OK;
err:
release_sem(mem->lock);
return B_NO_MEMORY;
}
/** Free memory
* \param mem heap handle
* \param blockID block id
* \param tag owner tag (must match tag passed to mem_alloc())
*/
status_t
mem_free(mem_info *mem, uint32 blockID, void *tag)
{
mem_block *block;
status_t status;
TRACE(("mem_free(mem %p, blockID=%ld, tag=%p)\n", mem, blockID, tag));
status = acquire_sem(mem->lock);
if (status != B_OK)
return status;
--blockID;
if (blockID >= mem->heap_entries) {
TRACE(("mem_free: invalid ID %lu\n", blockID));
goto err;
}
block = &mem->heap[blockID];
if (!block->allocated || block->tag != tag) {
TRACE(("mem_free: not owner\n"));
goto err;
}
freeblock(mem, block);
release_sem(mem->lock);
return B_OK;
err:
release_sem(mem->lock);
return B_BAD_VALUE;
}
/** Free all memory belonging to owner "tag" */
status_t
mem_freetag(mem_info *mem, void *tag)
{
mem_block *current;
status_t status;
TRACE(("mem_freetag(mem %p, tag=%p)\n", mem, tag));
status = acquire_sem(mem->lock);
if (status != B_OK)
return status;
for (current = mem->first; current; current = current->next) {
if (current->allocated && current->tag == tag)
current = freeblock(mem, current);
}
release_sem(mem->lock);
return B_OK;
}
@@ -1,16 +1,15 @@
/*
Copyright (c) 2002, Thomas Kurschel
* Copyright (c) 2002, Thomas Kurschel
* Distributed under the terms of the MIT license.
*/
Part of Radeon kernel driver
Graphics card detection
*/
/** Graphics card detection */
#include "radeon_driver.h"
#include <stdio.h>
#include <string.h>
// this table is gathered from different sources
@@ -1,23 +1,25 @@
/*
Copyright (c) 2002-2004, Thomas Kurschel
* Copyright (c) 2002-2004, Thomas Kurschel
* Distributed under the terms of the MIT license.
*/
Part of Radeon kernel driver
/*
Init and clean-up of devices
TBD: support for multiple virtual card per device is
TODO: support for multiple virtual card per device is
not implemented yet - there is only one per device;
apart from additional device names, we need proper
management of graphics mem to not interfere.
*/
#include "dac_regs.h"
#include "radeon_driver.h"
#include "mmio.h"
#include <PCI.h>
#include <stdio.h>
#include "dac_regs.h"
#include "mmio.h"
#include <string.h>
// helper macros for easier PCI access
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
@@ -309,17 +311,17 @@ status_t Radeon_FirstOpen( device_info *di )
// resolution of 2D register is 1K, resolution of CRTC etc. is higher,
// so 1K is the minimum block size;
// (CP cannot use local mem)
di->memmgr[mt_local] = mem_init( 0, di->local_mem_size, 1024,
di->local_mem_size / 1024 );
if( di->memmgr[mt_local] == NULL ) {
di->memmgr[mt_local] = mem_init("radeon local memory", 0, di->local_mem_size, 1024,
di->local_mem_size / 1024);
if (di->memmgr[mt_local] == NULL) {
result = B_NO_MEMORY;
goto err3;
}
// CP requires 4K alignment, which is the most restrictive I found
di->memmgr[mt_PCI] = mem_init( 0, di->pci_gart.buffer.size, 4096,
di->pci_gart.buffer.size / 4096 );
if( di->memmgr[mt_PCI] == NULL ) {
di->memmgr[mt_PCI] = mem_init("radeon PCI GART memory", 0, di->pci_gart.buffer.size, 4096,
di->pci_gart.buffer.size / 4096);
if (di->memmgr[mt_PCI] == NULL) {
result = B_NO_MEMORY;
goto err2;
}
@@ -1,17 +1,13 @@
/*
Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon kernel driver
Common header file
*/
* Copyright (c) 2002-2004, Thomas Kurschel
* Distributed under the terms of the MIT license.
*/
#ifndef _RADEON_DRIVER_H
#define _RADEON_DRIVER_H
#include "radeon_interface.h"
#include "memmgr.h"
#include "memory_manager.h"
#include <KernelExport.h>
#include <GraphicsDefs.h>