diff --git a/headers/private/graphics/common/memmgr.h b/headers/private/graphics/common/memmgr.h deleted file mode 100644 index d69262a3e4..0000000000 --- a/headers/private/graphics/common/memmgr.h +++ /dev/null @@ -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 - - -// 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 diff --git a/headers/private/graphics/common/memory_manager.h b/headers/private/graphics/common/memory_manager.h new file mode 100644 index 0000000000..a128116b3b --- /dev/null +++ b/headers/private/graphics/common/memory_manager.h @@ -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 + + +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 */ diff --git a/src/add-ons/kernel/drivers/graphics/common/Jamfile b/src/add-ons/kernel/drivers/graphics/common/Jamfile index 21c4c95800..0c30e291ce 100644 --- a/src/add-ons/kernel/drivers/graphics/common/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/common/Jamfile @@ -9,5 +9,5 @@ UsePrivateHeaders [ FDirName graphics common ] ; StaticLibrary libgraphicscommon.a : log_coll.c log_dump.c - memmgr.c + memory_manager.c ; diff --git a/src/add-ons/kernel/drivers/graphics/common/memmgr.c b/src/add-ons/kernel/drivers/graphics/common/memmgr.c deleted file mode 100644 index 105f0e4ca9..0000000000 --- a/src/add-ons/kernel/drivers/graphics/common/memmgr.c +++ /dev/null @@ -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 -#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" ); -} diff --git a/src/add-ons/kernel/drivers/graphics/common/memory_manager.c b/src/add-ons/kernel/drivers/graphics/common/memory_manager.c new file mode 100644 index 0000000000..520a4c678f --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/common/memory_manager.c @@ -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 +#include + + +//#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; +} diff --git a/src/add-ons/kernel/drivers/graphics/radeon/detect.c b/src/add-ons/kernel/drivers/graphics/radeon/detect.c index 37cf984d33..4d1376b721 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/detect.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/detect.c @@ -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 +#include // this table is gathered from different sources diff --git a/src/add-ons/kernel/drivers/graphics/radeon/init.c b/src/add-ons/kernel/drivers/graphics/radeon/init.c index 4cafea26bc..2ac425d2f0 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/init.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/init.c @@ -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 + #include -#include "dac_regs.h" -#include "mmio.h" +#include // 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; } diff --git a/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h b/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h index d76c9cb1b6..587eca680b 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h +++ b/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h @@ -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 #include