diff --git a/src/add-ons/kernel/drivers/graphics/common/Jamfile b/src/add-ons/kernel/drivers/graphics/common/Jamfile new file mode 100644 index 0000000000..1f08875eaa --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/common/Jamfile @@ -0,0 +1,13 @@ +SubDir OBOS_TOP src add-ons kernel drivers graphics common ; + +SubDirCcFlags -DENABLE_LOGGING -DLOG_INCLUDE_STARTUP ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics radeon ] ; +UsePrivateHeaders [ FDirName graphics common ] ; + +StaticLibrary graphicscommon : + log_coll.c + log_dump.c + memmgr.c +; diff --git a/src/add-ons/kernel/drivers/graphics/common/log_coll.c b/src/add-ons/kernel/drivers/graphics/common/log_coll.c new file mode 100644 index 0000000000..811e749e50 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/common/log_coll.c @@ -0,0 +1,129 @@ +/* + Copyright (c) 2002, Thomas Kurschel + + + Part of Radeon driver + + Both kernel and user space part. + (init and clean-up must be done in + kernel space). +*/ + + +#include +#include +#include +#include +#include "log_coll.h" +#include +#include + +typedef struct log_info_t { + char *log_buffer; + uint32 log_buffer_len; + uint32 log_buffer_pos; + area_id area; +} log_info; + +#ifdef ENABLE_LOGGING + + +// write one log entry +void log( log_info *li, uint16 what, const uint8 num_args, ... ) +{ + uint32 pos; + va_list vl; + log_entry *entry; + uint32 i; + uint32 entry_size; + + entry_size = sizeof( log_entry ) + (num_args - 1) * sizeof( uint32 ); + pos = atomic_add( &li->log_buffer_pos, entry_size ); + + if( li->log_buffer_pos > li->log_buffer_len ) { + atomic_add( &li->log_buffer_pos, -entry_size ); + return; + } + + entry = (log_entry *)&li->log_buffer[pos]; + + entry->tsc = read_tsc(); + entry->what = what; + entry->num_args = num_args; + + va_start( vl, num_args ); + for( i = 0; i < num_args; ++i ) { + entry->args[i] = va_arg( vl, uint32 ); + } + va_end( vl ); +} + +#ifdef LOG_INCLUDE_STARTUP + +// create log buffer +log_info *log_init( uint32 size ) +{ + log_info *li; + area_id area; + + // buffer must be accessible from user mem + // to allow logging from there as well; + // you cannot clone this area as there are + // pointers which would break (it wouldn't be + // hard to get rid of them, but I don't care + // and keep it as simple as possible) + area = create_area( "fast_logger", + (void **)&li, B_ANY_KERNEL_ADDRESS, + (sizeof( log_info ) + size + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1), + B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA ); + + if( area < 0 ) + panic( "Radeon Fast logger: cannot allocate %ld byte for logging data\n", size ); + + li->area = area; + li->log_buffer = (char *)li + sizeof( log_info ); + li->log_buffer_len = size; + li->log_buffer_pos = 0; + + return li; +} + +// clean-up logging +void log_exit( log_info *li ) +{ + li->log_buffer_pos = 0; + //free( li->log_buffer ); + delete_area( li->area ); +} + +#endif + +#endif + + +#ifdef LOG_INCLUDE_STARTUP + +// get *current* size of logging data +uint32 log_getsize( log_info *li ) +{ + if( li == NULL ) + return 0; + + dprintf( "RADEON -- log_getsize: log_pos %ld\n", li->log_buffer_pos ); + return li->log_buffer_pos; +} + +// get up to max_size bytes of logging data +void log_getcopy( log_info *li, void *dest, uint32 max_size ) +{ + if( li == NULL ) + return; + + dprintf( "RADEON -- log_getcopy: max_size %ld, log_pos %ld\n", + max_size, li->log_buffer_pos ); + memcpy( dest, li->log_buffer, min( li->log_buffer_pos, max_size )); + + li->log_buffer_pos = 0; +} + +#endif diff --git a/src/add-ons/kernel/drivers/graphics/common/log_dump.c b/src/add-ons/kernel/drivers/graphics/common/log_dump.c new file mode 100644 index 0000000000..6f8c62e27e --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/common/log_dump.c @@ -0,0 +1,73 @@ +/* + Copyright (c) 2002, Thomas Kurschel + + + Part of Radeon driver + + Fast logger - functions to create dump +*/ + + +#include +#include + +#include "log_coll.h" +#include "log_dump.h" +#include "log_enum.h" +#include "log_names.h" + +system_info sysinfo; + +// dump one entry +void log_printentry( FILE *logfile, log_entry *entry ) +{ + uint64 time; + uint32 min, sec, mill, mic; + + time = entry->tsc / (sysinfo.cpu_clock_speed / 1000000); + mic = time % 1000; + time /= 1000; + mill = time % 1000; + time /= 1000; + sec = time % 60; + time /= 60; + min = time; + + fprintf( logfile, "%03ld:%02ld:%03ld.%03ld ", min, sec, mill, mic ); + if( entry->what < sizeof( log_names ) / sizeof( log_names[0] ) ) + fprintf( logfile, log_names[entry->what] ); + else + fprintf( logfile, "unknown %ld", (uint32)entry->what ); + + if( entry->num_args > 0 ) { + uint32 i; + + fprintf( logfile, " (" ); + for( i = 0; i < entry->num_args; ++i ) { + if( i > 0 ) + fprintf( logfile, ", " ); + + fprintf( logfile, "0x%08lx", entry->args[i] ); + } + fprintf( logfile, ")" ); + } + + fprintf( logfile, "\n" ); +} + + +// dump entire log +void log_printall( FILE *logfile, char *buffer, uint32 buffer_len ) +{ + uint32 pos; + + get_system_info( &sysinfo ); + + for( pos = 0; pos < buffer_len; ) { + log_entry *entry; + + entry = (log_entry *)(buffer + pos); + log_printentry( logfile, entry/*, &tsc*/ ); + pos += sizeof( log_entry ) + (entry->num_args - 1) * sizeof( uint32 ); + } +} diff --git a/src/add-ons/kernel/drivers/graphics/common/memmgr.c b/src/add-ons/kernel/drivers/graphics/common/memmgr.c new file mode 100644 index 0000000000..3d10cc9da0 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/common/memmgr.c @@ -0,0 +1,273 @@ +/* + 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; + + 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; + + mem->heap = malloc( heap_entries * sizeof( mem_block )); + if( mem->heap == NULL ) + goto err3; + + for( i = 1; i < heap_entries; ++i ) + mem->heap[i].next = &mem->heap[i+1]; + + 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, "" ); + + free( mem->heap ); + 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" ); +}