OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [src/] [lib/] [memcache.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
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
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.