| 1 |
2 |
drasko |
/*
|
| 2 |
|
|
* Bitmap-based linked-listable fixed-size memory cache.
|
| 3 |
|
|
*
|
| 4 |
|
|
* Copyright (C) 2007 Bahadir Balban
|
| 5 |
|
|
*/
|
| 6 |
|
|
#include <l4/lib/memcache.h>
|
| 7 |
|
|
#include <l4/lib/string.h>
|
| 8 |
|
|
#include <l4/lib/printk.h>
|
| 9 |
|
|
#include INC_GLUE(memory.h)
|
| 10 |
|
|
#include <l4/lib/bit.h>
|
| 11 |
|
|
#include <l4/api/errno.h>
|
| 12 |
|
|
|
| 13 |
|
|
/* Allocate, clear and return element */
|
| 14 |
|
|
void *mem_cache_zalloc(struct mem_cache *cache)
|
| 15 |
|
|
{
|
| 16 |
|
|
void *elem = mem_cache_alloc(cache);
|
| 17 |
|
|
memset(elem, 0, cache->struct_size);
|
| 18 |
|
|
return elem;
|
| 19 |
|
|
}
|
| 20 |
|
|
|
| 21 |
|
|
/* Allocate another element from given @cache. Returns 0 when full. */
|
| 22 |
|
|
void *mem_cache_alloc(struct mem_cache *cache)
|
| 23 |
|
|
{
|
| 24 |
|
|
int bit;
|
| 25 |
|
|
int err;
|
| 26 |
|
|
|
| 27 |
|
|
if (cache->free > 0) {
|
| 28 |
|
|
if ((err = mutex_lock(&cache->mutex)) < 0)
|
| 29 |
|
|
return PTR_ERR(err); /* Interruptible mutex */
|
| 30 |
|
|
cache->free--;
|
| 31 |
|
|
if ((bit = find_and_set_first_free_bit(cache->bitmap,
|
| 32 |
|
|
cache->total)) < 0) {
|
| 33 |
|
|
printk("Error: Anomaly in cache occupied state.\n"
|
| 34 |
|
|
"Bitmap full although cache->free > 0\n");
|
| 35 |
|
|
BUG();
|
| 36 |
|
|
}
|
| 37 |
|
|
mutex_unlock(&cache->mutex);
|
| 38 |
|
|
return (void *)(cache->start + (cache->struct_size * bit));
|
| 39 |
|
|
} else {
|
| 40 |
|
|
/* Cache full */
|
| 41 |
|
|
return 0;
|
| 42 |
|
|
}
|
| 43 |
|
|
}
|
| 44 |
|
|
|
| 45 |
|
|
/* Free element at @addr in @cache. Return negative on error. */
|
| 46 |
|
|
int mem_cache_free(struct mem_cache *cache, void *addr)
|
| 47 |
|
|
{
|
| 48 |
|
|
unsigned int struct_addr = (unsigned int)addr;
|
| 49 |
|
|
unsigned int bit;
|
| 50 |
|
|
int err = 0;
|
| 51 |
|
|
|
| 52 |
|
|
/* Check boundary */
|
| 53 |
|
|
if (struct_addr < cache->start || struct_addr > cache->end)
|
| 54 |
|
|
return -1; /* Address doesn't belong to cache */
|
| 55 |
|
|
|
| 56 |
|
|
bit = ((struct_addr - cache->start) / cache->struct_size);
|
| 57 |
|
|
|
| 58 |
|
|
/*
|
| 59 |
|
|
* Check alignment:
|
| 60 |
|
|
* Find out if there was a lost remainder in last division.
|
| 61 |
|
|
* There shouldn't have been, because addresses are allocated at
|
| 62 |
|
|
* struct_size offsets from cache->start.
|
| 63 |
|
|
*/
|
| 64 |
|
|
if (((bit * cache->struct_size) + cache->start) != struct_addr) {
|
| 65 |
|
|
printk("Error: This address is not aligned on a predefined "
|
| 66 |
|
|
"structure address in this cache.\n");
|
| 67 |
|
|
err = -1;
|
| 68 |
|
|
return err;
|
| 69 |
|
|
}
|
| 70 |
|
|
|
| 71 |
|
|
if ((err = mutex_lock(&cache->mutex)) < 0)
|
| 72 |
|
|
return err; /* Interruptible mutex */
|
| 73 |
|
|
|
| 74 |
|
|
/* Check free/occupied state */
|
| 75 |
|
|
if (check_and_clear_bit(cache->bitmap, bit) < 0) {
|
| 76 |
|
|
printk("Error: Anomaly in cache occupied state:\n"
|
| 77 |
|
|
"Trying to free already free structure.\n");
|
| 78 |
|
|
err = -1;
|
| 79 |
|
|
goto out;
|
| 80 |
|
|
}
|
| 81 |
|
|
cache->free++;
|
| 82 |
|
|
if (cache->free > cache->total) {
|
| 83 |
|
|
printk("Error: Anomaly in cache occupied state:\n"
|
| 84 |
|
|
"More free elements than total.\n");
|
| 85 |
|
|
err = -1;
|
| 86 |
|
|
goto out;
|
| 87 |
|
|
}
|
| 88 |
|
|
out:
|
| 89 |
|
|
mutex_unlock(&cache->mutex);
|
| 90 |
|
|
return err;
|
| 91 |
|
|
}
|
| 92 |
|
|
|
| 93 |
|
|
/*
|
| 94 |
|
|
* Given a buffer start address, structure size, number of
|
| 95 |
|
|
* structs and alignment requirements, determines how much
|
| 96 |
|
|
* memory is needed from that starting address
|
| 97 |
|
|
*/
|
| 98 |
|
|
int mem_cache_bufsize(void *start, int struct_size, int nstructs, int aligned)
|
| 99 |
|
|
{
|
| 100 |
|
|
unsigned long start_address = (unsigned long)start;
|
| 101 |
|
|
int total_bytes, bwords, bitmap_size;
|
| 102 |
|
|
|
| 103 |
|
|
/* Word alignment requirement */
|
| 104 |
|
|
start_address = align_up(start_address, sizeof(int));
|
| 105 |
|
|
|
| 106 |
|
|
/* Total bytes to contain structures */
|
| 107 |
|
|
total_bytes = struct_size * nstructs;
|
| 108 |
|
|
|
| 109 |
|
|
/* Total words to contain bitmap */
|
| 110 |
|
|
bwords = nstructs >> 5;
|
| 111 |
|
|
|
| 112 |
|
|
/* An extra word if not a multiple of one word's bits */
|
| 113 |
|
|
if (nstructs & 0x1F)
|
| 114 |
|
|
bwords++;
|
| 115 |
|
|
|
| 116 |
|
|
/* Total bitmap bytes */
|
| 117 |
|
|
bitmap_size = bwords * sizeof(int);
|
| 118 |
|
|
|
| 119 |
|
|
/* Current would-be start address */
|
| 120 |
|
|
start_address += bitmap_size + total_bytes + sizeof(struct mem_cache);
|
| 121 |
|
|
|
| 122 |
|
|
/* Check alignment requirement */
|
| 123 |
|
|
if (aligned)
|
| 124 |
|
|
start_address = align_up(start_address, struct_size);
|
| 125 |
|
|
|
| 126 |
|
|
return start_address - (unsigned long)start;
|
| 127 |
|
|
}
|
| 128 |
|
|
|
| 129 |
|
|
struct mem_cache *mem_cache_init(void *bufstart, int cache_size,
|
| 130 |
|
|
int struct_size, unsigned int aligned)
|
| 131 |
|
|
{
|
| 132 |
|
|
void *start;
|
| 133 |
|
|
struct mem_cache *cache;
|
| 134 |
|
|
unsigned int area_start;
|
| 135 |
|
|
unsigned int *bitmap;
|
| 136 |
|
|
int bwords, total, bsize;
|
| 137 |
|
|
|
| 138 |
|
|
/* Align to nearest word boundary */
|
| 139 |
|
|
start = (void *)align_up(bufstart, sizeof(int));
|
| 140 |
|
|
cache_size -= (int)start - (int)bufstart;
|
| 141 |
|
|
cache = start;
|
| 142 |
|
|
|
| 143 |
|
|
if ((struct_size < 0) || (cache_size < 0) ||
|
| 144 |
|
|
((unsigned long)start == ~(0))) {
|
| 145 |
|
|
printk("Invalid parameters.\n");
|
| 146 |
|
|
return 0;
|
| 147 |
|
|
}
|
| 148 |
|
|
|
| 149 |
|
|
/*
|
| 150 |
|
|
* The cache definition itself is at the beginning.
|
| 151 |
|
|
* Skipping it to get to start of free memory. i.e. the cache.
|
| 152 |
|
|
*/
|
| 153 |
|
|
area_start = (unsigned long)start + sizeof(struct mem_cache);
|
| 154 |
|
|
cache_size -= sizeof(struct mem_cache);
|
| 155 |
|
|
|
| 156 |
|
|
if (cache_size < struct_size) {
|
| 157 |
|
|
printk("Cache too small for given struct_size\n");
|
| 158 |
|
|
return 0;
|
| 159 |
|
|
}
|
| 160 |
|
|
|
| 161 |
|
|
/* Get how much bitmap words occupy */
|
| 162 |
|
|
total = cache_size / struct_size;
|
| 163 |
|
|
bwords = total >> 5; /* Divide by 32 */
|
| 164 |
|
|
if (total & 0x1F) { /* Remainder? */
|
| 165 |
|
|
bwords++; /* Add one more word for remainder */
|
| 166 |
|
|
}
|
| 167 |
|
|
bsize = bwords * 4;
|
| 168 |
|
|
|
| 169 |
|
|
/* Reduce bitmap bytes from cache size */
|
| 170 |
|
|
cache_size -= bsize;
|
| 171 |
|
|
|
| 172 |
|
|
/* Recalculate total - it may or may not have changed */
|
| 173 |
|
|
total = cache_size / struct_size;
|
| 174 |
|
|
|
| 175 |
|
|
/* This should always catch too small caches */
|
| 176 |
|
|
if (total <= 0) {
|
| 177 |
|
|
printk("Cache too small for given struct_size\n");
|
| 178 |
|
|
return 0;
|
| 179 |
|
|
}
|
| 180 |
|
|
if (cache_size <= 0) {
|
| 181 |
|
|
printk("Cache too small for given struct_size\n");
|
| 182 |
|
|
return 0;
|
| 183 |
|
|
}
|
| 184 |
|
|
|
| 185 |
|
|
bitmap = (unsigned int *)area_start;
|
| 186 |
|
|
area_start = (unsigned int)(bitmap + bwords);
|
| 187 |
|
|
|
| 188 |
|
|
if (aligned) {
|
| 189 |
|
|
unsigned int addr = area_start;
|
| 190 |
|
|
unsigned int addr_aligned = align_up(area_start, struct_size);
|
| 191 |
|
|
unsigned int diff = addr_aligned - addr;
|
| 192 |
|
|
|
| 193 |
|
|
BUG_ON(diff >= struct_size);
|
| 194 |
|
|
cache_size -= diff;
|
| 195 |
|
|
|
| 196 |
|
|
/* Recalculate total */
|
| 197 |
|
|
total = cache_size / struct_size;
|
| 198 |
|
|
area_start = addr_aligned;
|
| 199 |
|
|
}
|
| 200 |
|
|
|
| 201 |
|
|
link_init(&cache->list);
|
| 202 |
|
|
cache->start = area_start;
|
| 203 |
|
|
cache->end = area_start + cache_size;
|
| 204 |
|
|
cache->total = total;
|
| 205 |
|
|
cache->free = cache->total;
|
| 206 |
|
|
cache->struct_size = struct_size;
|
| 207 |
|
|
cache->bitmap = bitmap;
|
| 208 |
|
|
|
| 209 |
|
|
mutex_init(&cache->mutex);
|
| 210 |
|
|
memset(cache->bitmap, 0, bwords*SZ_WORD);
|
| 211 |
|
|
|
| 212 |
|
|
return cache;
|
| 213 |
|
|
}
|
| 214 |
|
|
|
| 215 |
|
|
|