K2.6 patches and update.
[tomato.git] / release / src-rt / shared / nvram / nvram.c
blobc6f8985ea00d0c9cbfa7e542922065318f67fcaa
1 /*
2 * NVRAM variable manipulation (common)
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: nvram.c 241182 2011-02-17 21:50:03Z gmo $
21 #include <typedefs.h>
22 #include <bcmdefs.h>
23 #include <osl.h>
24 #include <bcmutils.h>
25 #include <siutils.h>
26 #include <bcmendian.h>
27 #include <bcmnvram.h>
28 #include <sbsdram.h>
30 extern struct nvram_tuple *_nvram_realloc(struct nvram_tuple *t, const char *name,
31 const char *value);
32 extern void _nvram_free(struct nvram_tuple *t);
33 extern int _nvram_read(void *buf);
35 char *_nvram_get(const char *name);
36 int _nvram_set(const char *name, const char *value);
37 int _nvram_unset(const char *name);
38 int _nvram_getall(char *buf, int count);
39 int _nvram_commit(struct nvram_header *header);
40 int _nvram_init(void *sih);
41 void _nvram_exit(void);
42 uint8 nvram_calc_crc(struct nvram_header *nvh);
44 static struct nvram_tuple *BCMINITDATA(nvram_hash)[257];
45 static struct nvram_tuple *nvram_dead;
47 /* Free all tuples. Should be locked. */
48 static void
49 BCMINITFN(nvram_free)(void)
51 uint i;
52 struct nvram_tuple *t, *next;
54 /* Free hash table */
55 for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
56 for (t = nvram_hash[i]; t; t = next) {
57 next = t->next;
58 _nvram_free(t);
60 nvram_hash[i] = NULL;
63 /* Free dead table */
64 for (t = nvram_dead; t; t = next) {
65 next = t->next;
66 _nvram_free(t);
68 nvram_dead = NULL;
70 /* Indicate to per-port code that all tuples have been freed */
71 _nvram_free(NULL);
74 /* String hash */
75 static INLINE uint
76 hash(const char *s)
78 uint hashval = 0;
80 while (*s)
81 hashval = 31 *hashval + *s++;
83 return hashval;
86 //#define NVRAM2HANDLER 1
89 * separte nvram into two part, for those bootloader can't handle large nvram well models
90 * nvram_header
92 * nvram_header2
96 #ifdef NVRAM2HANDLER
98 struct nvram_header *find_next_header(struct nvram_header *header, char *ptr)
100 struct nvram_header *hdr;
101 char *hdrptr;
103 hdrptr = (char *)header;
105 if(ptr>hdrptr) {
106 if((ptr-hdrptr)%16) {
107 hdrptr = ptr + (16-(ptr-hdrptr)%16);
109 else hdrptr = ptr;
111 else hdrptr = NULL;
113 hdr = (struct nvram_header *)hdrptr;
115 printk("header : %x %x %x\n", header, ptr, hdr);
117 return hdr;
120 /* (Re)initialize the hash table. Should be locked. */
121 static int
122 BCMINITFN(nvram_rehash)(struct nvram_header *header)
124 char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
125 struct nvram_header *hdrptr;
126 /* (Re)initialize hash table */
127 nvram_free();
129 hdrptr = header;
131 /* Parse and set "name=value\0 ... \0\0" */
132 name = (char *) &hdrptr[1];
133 end = (char *) hdrptr + NVRAM_SPACE - 2;
134 end[0] = end[1] = '\0';
136 again:
137 for (; *name; name = value + strlen(value) + 1) {
138 if (!(eq = strchr(name, '=')))
139 break;
140 *eq = '\0';
141 value = eq + 1;
142 _nvram_set(name, value);
143 *eq = '=';
146 printk("rehash %x %x\n", header, name);
148 int j;
150 for(j=0;j<64;j++) {
151 if(j%16==0) printk("\n");
152 printk("%x ", *(name-32+j));
154 printk("\n");
156 hdrptr = find_next_header(header, name+2);
158 if(hdrptr)
159 printk("magic: %x\n", hdrptr->magic);
161 if(hdrptr && hdrptr->magic==NVRAM_MAGIC) {
162 name = (char *)&hdrptr[1];
163 goto again;
166 /* Set special SDRAM parameters */
167 if (!_nvram_get("sdram_init")) {
168 sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16));
169 _nvram_set("sdram_init", buf);
171 if (!_nvram_get("sdram_config")) {
172 sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff));
173 _nvram_set("sdram_config", buf);
175 if (!_nvram_get("sdram_refresh")) {
176 sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff));
177 _nvram_set("sdram_refresh", buf);
179 if (!_nvram_get("sdram_ncdl")) {
180 sprintf(buf, "0x%08X", header->config_ncdl);
181 _nvram_set("sdram_ncdl", buf);
184 return 0;
186 #else
187 /* (Re)initialize the hash table. Should be locked. */
188 static int
189 BCMINITFN(nvram_rehash)(struct nvram_header *header)
191 char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
193 /* (Re)initialize hash table */
194 nvram_free();
196 /* Parse and set "name=value\0 ... \0\0" */
197 name = (char *) &header[1];
198 end = (char *) header + NVRAM_SPACE - 2;
199 end[0] = end[1] = '\0';
200 for (; *name; name = value + strlen(value) + 1) {
201 if (!(eq = strchr(name, '=')))
202 break;
203 *eq = '\0';
204 value = eq + 1;
205 _nvram_set(name, value);
206 *eq = '=';
209 /* Set special SDRAM parameters */
210 if (!_nvram_get("sdram_init")) {
211 sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16));
212 _nvram_set("sdram_init", buf);
214 if (!_nvram_get("sdram_config")) {
215 sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff));
216 _nvram_set("sdram_config", buf);
218 if (!_nvram_get("sdram_refresh")) {
219 sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff));
220 _nvram_set("sdram_refresh", buf);
222 if (!_nvram_get("sdram_ncdl")) {
223 sprintf(buf, "0x%08X", header->config_ncdl);
224 _nvram_set("sdram_ncdl", buf);
227 return 0;
229 #endif
231 /* Get the value of an NVRAM variable. Should be locked. */
232 char *
233 _nvram_get(const char *name)
235 uint i;
236 struct nvram_tuple *t;
237 char *value;
239 if (!name)
240 return NULL;
242 /* Hash the name */
243 i = hash(name) % ARRAYSIZE(nvram_hash);
245 /* Find the associated tuple in the hash table */
246 for (t = nvram_hash[i]; t && strcmp(t->name, name); t = t->next);
248 value = t ? t->value : NULL;
250 return value;
253 /* Set the value of an NVRAM variable. Should be locked. */
255 BCMINITFN(_nvram_set)(const char *name, const char *value)
257 uint i;
258 struct nvram_tuple *t, *u, **prev;
260 /* Hash the name */
261 i = hash(name) % ARRAYSIZE(nvram_hash);
263 /* Find the associated tuple in the hash table */
264 for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name);
265 prev = &t->next, t = *prev);
267 /* (Re)allocate tuple */
268 if (!(u = _nvram_realloc(t, name, value)))
269 return -12; /* -ENOMEM */
271 /* Value reallocated */
272 if (t && t == u)
273 return 0;
275 /* Move old tuple to the dead table */
276 if (t) {
277 *prev = t->next;
278 t->next = nvram_dead;
279 nvram_dead = t;
282 /* Add new tuple to the hash table */
283 u->next = nvram_hash[i];
284 nvram_hash[i] = u;
286 return 0;
289 /* Unset the value of an NVRAM variable. Should be locked. */
291 BCMINITFN(_nvram_unset)(const char *name)
293 uint i;
294 struct nvram_tuple *t, **prev;
296 if (!name)
297 return 0;
299 /* Hash the name */
300 i = hash(name) % ARRAYSIZE(nvram_hash);
302 /* Find the associated tuple in the hash table */
303 for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name);
304 prev = &t->next, t = *prev);
306 /* Move it to the dead table */
307 if (t) {
308 *prev = t->next;
309 t->next = nvram_dead;
310 nvram_dead = t;
313 return 0;
316 /* Get all NVRAM variables. Should be locked. */
318 _nvram_getall(char *buf, int count)
320 uint i;
321 struct nvram_tuple *t;
322 int len = 0;
324 bzero(buf, count);
326 /* Write name=value\0 ... \0\0 */
327 for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
328 for (t = nvram_hash[i]; t; t = t->next) {
329 if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1))
330 len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1;
331 else
332 break;
336 return 0;
339 #ifdef NVRAM2HANDLER
340 /* Regenerate NVRAM. Should be locked. */
342 BCMINITFN(_nvram_commit)(struct nvram_header *header)
344 char *init, *config, *refresh, *ncdl;
345 char *ptr, *end;
346 int i;
347 struct nvram_tuple *t;
348 struct nvram_header *hdrptr;
349 int starti, next;
351 hdrptr=header;
352 bzero(hdrptr, NVRAM_SPACE);
353 /* Leave space for a double NUL at the end */
354 end = (char *) header + NVRAM_SPACE - 2;
355 starti=0;
356 next = 0;
358 again:
360 /* Regenerate header */
361 hdrptr->magic = NVRAM_MAGIC;
362 hdrptr->crc_ver_init = (NVRAM_VERSION << 8);
363 if (!(init = _nvram_get("sdram_init")) ||
364 !(config = _nvram_get("sdram_config")) ||
365 !(refresh = _nvram_get("sdram_refresh")) ||
366 !(ncdl = _nvram_get("sdram_ncdl"))) {
367 hdrptr->crc_ver_init |= SDRAM_INIT << 16;
368 hdrptr->config_refresh = SDRAM_CONFIG;
369 hdrptr->config_refresh |= SDRAM_REFRESH << 16;
370 hdrptr->config_ncdl = 0;
371 } else {
372 hdrptr->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16;
373 hdrptr->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff;
374 hdrptr->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16;
375 hdrptr->config_ncdl = bcm_strtoul(ncdl, NULL, 0);
378 /* Clear data area */
379 ptr = (char *) hdrptr + sizeof(struct nvram_header);
381 /* Write out all tuples */
382 for (i = starti; i < ARRAYSIZE(nvram_hash); i++) {
383 for (t = nvram_hash[i]; t; t = t->next) {
384 if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
385 break;
386 ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
388 if(starti==0 && (ptr-(char *)hdrptr)>(NVRAM_SPACE/2)) {
389 starti = i+1;
390 printk("next hash table: %x\n", i);
391 break;
395 /* End with a double NUL */
396 ptr += 2;
398 /* Set new length */
399 hdrptr->len = ROUNDUP(ptr - (char *) hdrptr, 4);
401 /* Set new CRC8 */
402 hdrptr->crc_ver_init |= nvram_calc_crc(hdrptr);
404 printk("commit %x %x %d\n", header, ptr, i);
405 hdrptr = find_next_header(header, ptr);
407 if(hdrptr && i<ARRAYSIZE(nvram_hash)) {
408 goto again;
411 /* Reinitialize hash table */
412 return nvram_rehash(header);
414 #else
415 /* Regenerate NVRAM. Should be locked. */
417 BCMINITFN(_nvram_commit)(struct nvram_header *header)
419 char *init, *config, *refresh, *ncdl;
420 char *ptr, *end;
421 int i;
422 struct nvram_tuple *t;
424 /* Regenerate header */
425 header->magic = NVRAM_MAGIC;
426 header->crc_ver_init = (NVRAM_VERSION << 8);
427 if (!(init = _nvram_get("sdram_init")) ||
428 !(config = _nvram_get("sdram_config")) ||
429 !(refresh = _nvram_get("sdram_refresh")) ||
430 !(ncdl = _nvram_get("sdram_ncdl"))) {
431 header->crc_ver_init |= SDRAM_INIT << 16;
432 header->config_refresh = SDRAM_CONFIG;
433 header->config_refresh |= SDRAM_REFRESH << 16;
434 header->config_ncdl = 0;
435 } else {
436 header->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16;
437 header->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff;
438 header->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16;
439 header->config_ncdl = bcm_strtoul(ncdl, NULL, 0);
442 /* Clear data area */
443 ptr = (char *) header + sizeof(struct nvram_header);
444 bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header));
446 /* Leave space for a double NUL at the end */
447 end = (char *) header + NVRAM_SPACE - 2;
449 /* Write out all tuples */
450 for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
451 for (t = nvram_hash[i]; t; t = t->next) {
452 if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
453 break;
454 ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
458 /* End with a double NUL */
459 ptr += 2;
461 /* Set new length */
462 header->len = ROUNDUP(ptr - (char *) header, 4);
464 /* Set new CRC8 */
465 header->crc_ver_init |= nvram_calc_crc(header);
467 /* Reinitialize hash table */
468 return nvram_rehash(header);
470 #endif
472 /* Initialize hash table. Should be locked. */
474 BCMINITFN(_nvram_init)(void *sih)
476 struct nvram_header *header;
477 int ret;
480 if (!(header = (struct nvram_header *) MALLOC(si_osh(sih), NVRAM_SPACE))) {
481 printf("nvram_init: out of memory\n");
482 return -12; /* -ENOMEM */
484 printf("_nvram_init: allocat header: %lu, size= %lu\n", header, NVRAM_SPACE);
485 if ((ret = _nvram_read(header)) == 0 &&
486 header->magic == NVRAM_MAGIC)
487 nvram_rehash(header);
489 MFREE(si_osh(sih), header, NVRAM_SPACE);
490 return ret;
493 /* Free hash table. Should be locked. */
494 void
495 BCMINITFN(_nvram_exit)(void)
497 nvram_free();
500 /* returns the CRC8 of the nvram */
501 uint8
502 BCMINITFN(nvram_calc_crc)(struct nvram_header *nvh)
504 struct nvram_header tmp;
505 uint8 crc;
507 /* Little-endian CRC8 over the last 11 bytes of the header */
508 tmp.crc_ver_init = htol32((nvh->crc_ver_init & NVRAM_CRC_VER_MASK));
509 tmp.config_refresh = htol32(nvh->config_refresh);
510 tmp.config_ncdl = htol32(nvh->config_ncdl);
512 crc = hndcrc8((uint8 *) &tmp + NVRAM_CRC_START_POSITION,
513 sizeof(struct nvram_header) - NVRAM_CRC_START_POSITION,
514 CRC8_INIT_VALUE);
516 /* Continue CRC8 over data bytes */
517 crc = hndcrc8((uint8 *) &nvh[1], nvh->len - sizeof(struct nvram_header), crc);
519 return crc;