* - IO Cache
*
* By thePowersGang (John Hodge)
+ *
+ * TODO: Convert to use spare physical pages instead
*/
#define DEBUG 0
#include <acess.h>
// === TYPES ===
typedef struct sIOCache_Ent tIOCache_Ent;
+typedef struct sIOCache_PageInfo tIOCache_PageInfo;
// === STRUCTURES ===
struct sIOCache_Ent
Uint8 Data[];
};
+struct sIOCache_PageInfo
+{
+ tIOCache_PageInfo *GlobalNext;
+ tIOCache_PageInfo *CacheNext;
+ tIOCache *Owner;
+ tPAddr BasePhys;
+ Uint64 BaseOffset;
+};
+
struct sIOCache
{
tIOCache *Next;
int SectorSize;
- int Lock;
+ tMutex Lock;
int Mode;
Uint32 ID;
tIOCache_WriteCallback Write;
};
// === GLOBALS ===
- int glIOCache_Caches;
+tShortSpinlock glIOCache_Caches;
tIOCache *gIOCache_Caches = NULL;
int giIOCache_NumCaches = 0;
+tIOCache_PageInfo *gIOCache_GlobalPages;
// === CODE ===
/**
*/
tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
{
- tIOCache *ret = malloc( sizeof(tIOCache) );
+ tIOCache *ret = calloc( 1, sizeof(tIOCache) );
// Sanity Check
if(!ret) return NULL;
ret->ID = ID;
ret->Write = Write;
ret->CacheSize = CacheSize;
- ret->CacheUsed = 0;
- ret->Entries = 0;
// Append to list
- LOCK( &glIOCache_Caches );
+ SHORTLOCK( &glIOCache_Caches );
ret->Next = gIOCache_Caches;
gIOCache_Caches = ret;
- RELEASE( &glIOCache_Caches );
+ SHORTREL( &glIOCache_Caches );
// Return
return ret;
*/
int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
{
- tIOCache_Ent *ent;
ENTER("pCache XSector pBuffer", Cache, Sector, Buffer);
}
// Lock
- LOCK( &Cache->Lock );
+ Mutex_Acquire( &Cache->Lock );
if(Cache->CacheSize == 0) {
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
LEAVE('i', -1);
return -1;
}
-
+
+ #if IOCACHE_USE_PAGES
+ tIOCache_PageInfo *page;
+ size_t offset = (Sector*Cache->SectorSize) % PAGE_SIZE;
+ Uint64 wanted_base = (Sector*Cache->SectorSize) & ~(PAGE_SIZE-1);
+ for( page = Cache->Pages; page; page = page->CacheNext )
+ {
+ void *tmp;
+ if(page->BaseOffset < WantedBase) continue;
+ if(page->BaseOffset > WantedBase) break;
+ tmp = MM_MapTemp( page->BasePhys );
+ memcpy( Buffer, tmp + offset, Cache->SectorSize );
+ MM_FreeTemp( tmp );
+ }
+ #else
+ tIOCache_Ent *ent;
// Search the list
for( ent = Cache->Entries; ent; ent = ent->Next )
{
if( ent->Num == Sector ) {
memcpy(Buffer, ent->Data, Cache->SectorSize);
ent->LastAccess = now();
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
LEAVE('i', 1);
return 1;
}
// it's not there
if(ent->Num > Sector) break;
}
+ #endif
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
LEAVE('i', 0);
return 0;
}
return -1;
// Lock
- LOCK( &Cache->Lock );
+ Mutex_Acquire( &Cache->Lock );
if(Cache->CacheSize == 0) {
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
return -1;
}
{
// Is it already here?
if( ent->Num == Sector ) {
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
return 0;
}
oldestPrev = prev;
}
}
+ if( !oldest ) {
+ Log_Error("IOCache", "Cache full, but also empty");
+ return -1;
+ }
// Remove from list, write back and free
oldestPrev->Next = oldest->Next;
if(oldest->LastWrite && Cache->Mode != IOCACHE_VIRTUAL)
Cache->CacheUsed ++;
// Release Spinlock
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
// Return success
return 1;
if(!Cache || !Buffer)
return -1;
// Lock
- LOCK( &Cache->Lock );
+ Mutex_Acquire( &Cache->Lock );
if(Cache->CacheSize == 0) {
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
return -1;
}
ent->LastWrite = 0;
}
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
return 1;
}
// It's a sorted list, so as soon as we go past `Sector` we know
if(ent->Num > Sector) break;
}
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
return 0;
}
if( Cache->Mode == IOCACHE_VIRTUAL ) return;
// Lock
- LOCK( &Cache->Lock );
+ Mutex_Acquire( &Cache->Lock );
if(Cache->CacheSize == 0) {
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
return;
}
ent->LastWrite = 0;
}
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
}
/**
tIOCache_Ent *ent, *prev = NULL;
// Lock
- LOCK( &Cache->Lock );
+ Mutex_Acquire( &Cache->Lock );
if(Cache->CacheSize == 0) {
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
return;
}
Cache->CacheSize = 0;
- RELEASE( &Cache->Lock );
+ Mutex_Release( &Cache->Lock );
// Remove from list
- LOCK( &glIOCache_Caches );
+ SHORTLOCK( &glIOCache_Caches );
{
- tIOCache *ent;
- tIOCache *prev = (tIOCache*)&gIOCache_Caches;
- for(ent = gIOCache_Caches;
- ent;
- prev = ent, ent = ent->Next )
+ tIOCache *cache;
+ tIOCache *prev_cache = (tIOCache*)&gIOCache_Caches;
+ for(cache = gIOCache_Caches;
+ cache;
+ prev_cache = cache, cache = cache->Next )
{
- if(ent == Cache) {
- prev->Next = ent->Next;
+ if(cache == Cache) {
+ prev_cache->Next = cache->Next;
break;
}
}
}
- RELEASE( &glIOCache_Caches );
+ SHORTREL( &glIOCache_Caches );
free(Cache);
}