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

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [conts/] [libmem/] [memcache/] [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 <memcache/memcache.h>
7
#include <string.h>
8
#include <stdio.h>
9
 
10
/* Some definitions from glue/memory.h */
11
#define align_up(addr, size)            ((((unsigned long)addr) + (size - 1)) & (~(size - 1)))
12
#define SZ_WORD                 sizeof(unsigned long)
13
#define WORD_BITS               32
14
#define BITWISE_GETWORD(x)      (x >> 5) /* Divide by 32 */
15
#define BITWISE_GETBIT(x)       (1 << (x % WORD_BITS))
16
 
17
static int find_and_set_first_free_bit(u32 *word, unsigned int limit)
18
{
19
        int success = 0;
20
        int i;
21
 
22
        for(i = 0; i < limit; i++) {
23
                /* Find first unset bit */
24
                if (!(word[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i))) {
25
                        /* Set it */
26
                        word[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i);
27
                        success = 1;
28
                        break;
29
                }
30
        }
31
        /* Return bit just set */
32
        if (success)
33
                return i;
34
        else
35
                return -1;
36
}
37
 
38
static int check_and_clear_bit(u32 *word, int bit)
39
{
40
        /* Check that bit was set */
41
        if (word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit)) {
42
                word[BITWISE_GETWORD(bit)] &= ~BITWISE_GETBIT(bit);
43
                return 0;
44
        } else {
45
                //printf("Trying to clear already clear bit\n");
46
                return -1;
47
        }
48
}
49
 
50
/* Allocate, clear and return element */
51
void *mem_cache_zalloc(struct mem_cache *cache)
52
{
53
        void *elem = mem_cache_alloc(cache);
54
        memset(elem, 0, cache->struct_size);
55
        return elem;
56
}
57
 
58
/* Allocate another element from given @cache. Returns 0 when full. */
59
void *mem_cache_alloc(struct mem_cache *cache)
60
{
61
        int bit;
62
        if (cache->free > 0) {
63
                /* NOTE: If needed, must lock here */
64
                cache->free--;
65
                if ((bit = find_and_set_first_free_bit(cache->bitmap,
66
                                                       cache->total)) < 0) {
67
                        printk("Error: Anomaly in cache occupied state.\n"
68
                               "Bitmap full although cache->free > 0\n");
69
                        BUG();
70
                }
71
                /* NOTE: If needed, must unlock here */
72
                return (void *)(cache->start + (cache->struct_size * bit));
73
        } else {
74
                /* Cache full */
75
                return 0;
76
        }
77
}
78
 
79
/* Free element at @addr in @cache. Return negative on error. */
80
int mem_cache_free(struct mem_cache *cache, void *addr)
81
{
82
        unsigned int struct_addr = (unsigned int)addr;
83
        unsigned int bit;
84
        int err = 0;
85
 
86
        /* Check boundary */
87
        if (struct_addr < cache->start || struct_addr > cache->end) {
88
                printk("Error: This address doesn't belong to this cache.\n");
89
                return -1;
90
        }
91
        bit = ((struct_addr - cache->start) / cache->struct_size);
92
 
93
        /* Check alignment:
94
         * Find out if there was a lost remainder in last division.
95
         * There shouldn't have been, because addresses are allocated at
96
         * struct_size offsets from cache->start. */
97
        if (((bit * cache->struct_size) + cache->start) != struct_addr) {
98
                printk("Error: This address is not aligned on a predefined "
99
                       "structure address in this cache.\n");
100
                err = -1;
101
                return err;
102
        }
103
        /* NOTE: If needed, must lock here */
104
        /* Check free/occupied state */
105
        if (check_and_clear_bit(cache->bitmap, bit) < 0) {
106
                printk("Error: Anomaly in cache occupied state:\n"
107
                       "Trying to free already free structure.\n");
108
                err = -1;
109
                goto out;
110
        }
111
        cache->free++;
112
        if (cache->free > cache->total) {
113
                printk("Error: Anomaly in cache occupied state:\n"
114
                       "More free elements than total.\n");
115
                err = -1;
116
                goto out;
117
        }
118
out:
119
        /* NOTE: If locked, must unlock here */
120
        return err;
121
}
122
 
123
struct mem_cache *mem_cache_init(void *start,
124
                                 int cache_size,
125
                                 int struct_size,
126
                                 unsigned int aligned)
127
{
128
        struct mem_cache *cache = start;
129
        unsigned int area_start;
130
        unsigned int *bitmap;
131
        int bwords_in_structs;
132
        int bwords;
133
        int total;
134
        int bsize;
135
 
136
        if ((struct_size < 0) || (cache_size < 0) ||
137
            ((unsigned long)start == ~(0))) {
138
                printk("Invalid parameters.\n");
139
                return 0;
140
        }
141
 
142
        /* The cache definition itself is at the beginning.
143
         * Skipping it to get to start of free memory. i.e. the cache. */
144
        area_start = (unsigned long)start + sizeof(struct mem_cache);
145
        cache_size -= sizeof(struct mem_cache);
146
 
147
        if (cache_size < struct_size) {
148
                printk("Cache too small for given struct_size\n");
149
                return 0;
150
        }
151
 
152
        /* Get how much bitmap words occupy */
153
        total = cache_size / struct_size;
154
        bwords = total >> 5;    /* Divide by 32 */
155
        if (total & 0x1F) {     /* Remainder? */
156
                bwords++;       /* Add one more word for remainder */
157
        }
158
 
159
        bsize = bwords * 4;
160
 
161
        /* This many structures will be chucked from cache for bitmap space */
162
        bwords_in_structs = ((bsize) / struct_size) + 1;
163
 
164
        /* Total structs left after deducing bitmaps */
165
        total = total - bwords_in_structs;
166
        cache_size -= bsize;
167
 
168
        /* This should always catch too small caches */
169
        if (total <= 0) {
170
                printk("Cache too small for given struct_size\n");
171
                return 0;
172
        }
173
        if (cache_size <= 0) {
174
                printk("Cache too small for given struct_size\n");
175
                return 0;
176
        }
177
        bitmap = (unsigned int *)area_start;
178
        area_start = (unsigned int)(bitmap + bwords);
179
        if (aligned) {
180
                unsigned int addr = area_start;
181
                unsigned int addr_aligned = align_up(area_start, struct_size);
182
                unsigned int diff = addr_aligned - addr;
183
 
184
                BUG_ON(diff >= struct_size);
185
                cache_size -= diff;
186
                area_start = addr_aligned;
187
        }
188
 
189
        /* Now recalculate total over cache bytes left */
190
        total = cache_size / struct_size;
191
 
192
        link_init(&cache->list);
193
        cache->start = area_start;
194
        cache->end = area_start + cache_size;
195
        cache->total = total;
196
        cache->free = cache->total;
197
        cache->struct_size = struct_size;
198
        cache->bitmap = bitmap;
199
 
200
        /* NOTE: If needed, must initialise lock here */
201
        memset(cache->bitmap, 0, bwords*SZ_WORD);
202
 
203
        return cache;
204
}
205
 
206
 

powered by: WebSVN 2.1.0

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