00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <agnix/agnix.h>
00015 #include <agnix/init.h>
00016 #include <agnix/memory.h>
00017 #include <agnix/list.h>
00018 #include <agnix/errno.h>
00019 #include <agnix/spinlock.h>
00020 #include <agnix/console.h>
00021
00022 #define HASH_ENTRIES ((PAGE_SIZE - sizeof(struct hash_table_s)) >> 3)
00023 #define MAX_HASH_TABLES 16
00024 #define MAX_HASH_ORDER 16
00025
00026 #define PSEUDO_KEY_FREE 0
00027 #define PSEUDO_KEY_DELETED 1
00028 #define PSEUDO_KEY_BUSY 2
00029
00030 #define find_hash_table(hashd) (&hash_tables[hashd])
00031
00032 #define HASH_DEBUG 0
00033 #define MOD_NAME "HASH: "
00034
00035 struct hash_entry_s {
00036 u32 hash_key;
00037 u32 hash_addr;
00038 int hash_status;
00039 };
00040
00041 struct hash_table_s {
00042 char *hash_name;
00043 int max_entries;
00044 int cur_entries;
00045 int page_order;
00046 int hashd;
00047
00048 u32 (*hash_fn)(u32 key);
00049 struct hash_entry_s *hash_entry;
00050 spinlock_t hash_lock;
00051 };
00052
00053 struct hash_table_s hash_tables[MAX_HASH_TABLES];
00054
00055 u32 hash_fn_default(u32 key)
00056 {
00057 return key;
00058 }
00059
00060 u32 hash_math_pseudo(struct hash_table_s *hash_table_ptr, u32 hash_key)
00061 {
00062 if (hash_table_ptr->hash_fn)
00063 return hash_table_ptr->hash_fn(hash_key);
00064 else
00065 return hash_key;
00066 }
00067
00068 void hash_count_entries(int hashd)
00069 {
00070 struct hash_table_s *hash_table_ptr;
00071
00072 hash_table_ptr = find_hash_table(hashd);
00073 printk("hash_ptr %x\n", hash_table_ptr);
00074 printk("hash_max_entries %x\n", hash_table_ptr->max_entries);
00075 printk("hash_cur_entries %x\n", hash_table_ptr->cur_entries);
00076 }
00077
00078 int hash_entry_add(int hashd, u32 hash_key, u32 hash_addr)
00079 {
00080 struct hash_table_s *hash_table_ptr;
00081 struct hash_entry_s *hash_entry;
00082 u32 pseudo_key = 0;
00083 int loops;
00084 u32 flags;
00085
00086 spin_lock_irqsave(&hash_table_ptr->hash_lock, flags);
00087
00088 hash_table_ptr = find_hash_table(hashd);
00089
00090 if (!hash_table_ptr->max_entries)
00091 return -1;
00092
00093 hash_entry = hash_table_ptr->hash_entry;
00094 pseudo_key = hash_math_pseudo(hash_table_ptr, hash_key) % hash_table_ptr->max_entries;
00095
00096 loops = 0;
00097 do {
00098 if (hash_entry[pseudo_key].hash_status == PSEUDO_KEY_BUSY) {
00099 pseudo_key = (pseudo_key + 1) % hash_table_ptr->max_entries;
00100 } else {
00101 hash_entry[pseudo_key].hash_key = hash_key;
00102 hash_entry[pseudo_key].hash_addr = hash_addr;
00103 hash_entry[pseudo_key].hash_status = PSEUDO_KEY_BUSY;
00104 hash_table_ptr->cur_entries++;
00105 spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00106 return 0;
00107 }
00108
00109 loops++;
00110
00111 } while(loops < hash_table_ptr->max_entries);
00112
00113 spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00114
00115 return -1;
00116 }
00117
00118 int hash_entry_del(int hashd, u32 hash_key)
00119 {
00120 struct hash_table_s *hash_table_ptr;
00121 struct hash_entry_s *hash_entry;
00122 u32 pseudo_key = 0;
00123 int loops;
00124 u32 flags;
00125
00126 spin_lock_irqsave(&hash_table_ptr->hash_lock, flags);
00127
00128 hash_table_ptr = find_hash_table(hashd);
00129 if (!hash_table_ptr->max_entries)
00130 return -1;
00131
00132 hash_entry = hash_table_ptr->hash_entry;
00133 pseudo_key = hash_math_pseudo(hash_table_ptr, hash_key) % hash_table_ptr->max_entries;
00134
00135 loops = 0;
00136 do {
00137
00138 if (hash_entry[pseudo_key].hash_status == PSEUDO_KEY_FREE) {
00139 break;
00140 }
00141
00142 if ((hash_entry[pseudo_key].hash_status != PSEUDO_KEY_BUSY) ||
00143 ((u32)hash_entry[pseudo_key].hash_key != (u32)hash_key)) {
00144 pseudo_key = (pseudo_key + 1) % hash_table_ptr->max_entries;
00145 }
00146 else {
00147 hash_entry[pseudo_key].hash_status = PSEUDO_KEY_DELETED;
00148 spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00149 return 0;
00150 }
00151
00152 loops++;
00153
00154 } while(loops < hash_table_ptr->max_entries);
00155
00156 spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00157 return -1;
00158 }
00159
00160 u32 hash_entry_find(int hashd, u32 hash_key)
00161 {
00162 struct hash_table_s *hash_table_ptr;
00163 struct hash_entry_s *hash_entry;
00164 u32 pseudo_key = 0;
00165 int loops;
00166 u32 flags;
00167
00168 spin_lock_irqsave(&hash_table_ptr->hash_lock, flags);
00169
00170 hash_table_ptr = find_hash_table(hashd);
00171 if (!hash_table_ptr->max_entries)
00172 return 0;
00173
00174 hash_entry = hash_table_ptr->hash_entry;
00175 pseudo_key = hash_math_pseudo(hash_table_ptr, hash_key) % hash_table_ptr->max_entries;
00176
00177 loops = 0;
00178 do {
00179 if (hash_entry[pseudo_key].hash_status == PSEUDO_KEY_FREE)
00180 break;
00181
00182 if ((hash_entry[pseudo_key].hash_status != PSEUDO_KEY_BUSY) ||
00183 ((u32)hash_entry[pseudo_key].hash_key != (u32)hash_key)) {
00184 pseudo_key = (pseudo_key + 1) % hash_table_ptr->max_entries;
00185 }
00186 else {
00187
00188 spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00189 return hash_entry[pseudo_key].hash_addr;
00190 }
00191
00192 loops++;
00193
00194 } while(loops < hash_table_ptr->max_entries);
00195
00196 spin_unlock_irqrestore(&hash_table_ptr->hash_lock, flags);
00197
00198 return 0;
00199 }
00200
00201 static int get_empty_hash_table(void)
00202 {
00203 u32 flags;
00204 int i;
00205
00206 for (i = 0; i < MAX_HASH_TABLES; i++) {
00207 spin_lock_irqsave(&hash_tables[i].hash_lock, flags);
00208 if (!hash_tables[i].cur_entries &&
00209 !hash_tables[i].max_entries) {
00210 spin_unlock_irqrestore(&hash_tables[i].hash_lock, flags);
00211 return i;
00212 }
00213
00214 spin_unlock_irqrestore(&hash_tables[i].hash_lock, flags);
00215 }
00216
00217 return -1;
00218 }
00219
00220 static void put_empty_hash_table(int hashd)
00221 {
00222 u32 flags;
00223
00224 spin_lock_irqsave(&hash_tables[hashd].hash_lock, flags);
00225 memset(&hash_tables[hashd], 0, sizeof(struct hash_table_s));
00226 spin_unlock_irqrestore(&hash_tables[hashd].hash_lock, flags);
00227 }
00228
00229 int register_hash_table(char *name, u32 rows, u32 (*hash_fn)(u32 key))
00230 {
00231 struct hash_table_s *hash_table;
00232 struct hash_entry_s *hash_entry;
00233 int page_order = 0;
00234 int hashd;
00235 int i;
00236
00237 hashd = get_empty_hash_table();
00238 if (hashd == -1)
00239 return -EAGAIN;
00240
00241 for (i = 0; i < MAX_HASH_ORDER; i++) {
00242 if (rows < (((1 << i) * PAGE_SIZE) / sizeof(struct hash_entry_s))) {
00243 page_order = i;
00244 break;
00245 }
00246 }
00247
00248 if (i == MAX_HASH_ORDER)
00249 return -EINVAL;
00250
00251 hash_table = &hash_tables[hashd];
00252 hash_entry = (struct hash_entry_s *)get_free_pages(page_order);
00253
00254 if (!hash_table) {
00255 put_empty_hash_table(hashd);
00256 return -ENOMEM;
00257 }
00258
00259 if (hash_fn)
00260 hash_table->hash_fn = hash_fn;
00261 else
00262 hash_table->hash_fn = hash_fn_default;
00263
00264 hash_table->hash_name = name;
00265 hash_table->max_entries = ((1 << page_order) * PAGE_SIZE) / sizeof(struct hash_entry_s);
00266 hash_table->cur_entries = 0;
00267 hash_table->page_order = page_order;
00268 hash_table->hashd = hashd;
00269 hash_table->hash_entry = hash_entry;
00270
00271 for (i = 0; i < hash_table->max_entries; i++)
00272 hash_table->hash_entry[i].hash_status = PSEUDO_KEY_FREE;
00273
00274 #if HASH_DEBUG
00275 printk(MOD_NAME "registering %s hashing table (%d rows/%d pages)\n", name, hash_table->max_entries, page_order);
00276 #endif
00277
00278 spin_lock_init(&hash_table->hash_lock);
00279
00280 return hashd;
00281 }
00282
00283 int unregister_hash_table(int hashd)
00284 {
00285 struct hash_table_s *hash_table_ptr;
00286
00287 hash_table_ptr = find_hash_table(hashd);
00288
00289 if (hash_table_ptr) {
00290 put_free_pages((u32)hash_table_ptr->hash_entry, (u8)(hash_table_ptr->page_order));
00291 put_free_pages((u32)hash_table_ptr, 0);
00292 }
00293
00294 return 0;
00295 }
00296
00297 int hash_static_init(void)
00298 {
00299 int i;
00300
00301 for (i = 0; i < MAX_HASH_TABLES; i++) {
00302 memset((void *)&hash_tables[i], 0, sizeof(struct hash_table_s));
00303 }
00304
00305 return 0;
00306 }
00307