GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / shared / nvram_rw.c
blob663d22bc4a4e70dfffd0a25ee43266c3ba82f745
1 /*
2 * NVRAM variable manipulation (direct mapped flash)
4 * Copyright (C) 2012, 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_rw.c 258972 2011-05-11 08:57:26Z $
21 #include <bcm_cfg.h>
22 #include <typedefs.h>
23 #include <bcmdefs.h>
24 #include <osl.h>
25 #include <bcmutils.h>
26 #include <siutils.h>
27 #include <bcmnvram.h>
28 #include <bcmendian.h>
29 #include <flashutl.h>
30 #include <hndsoc.h>
31 #include <sbchipc.h>
32 #include <LzmaDec.h>
33 #ifdef NFLASH_SUPPORT
34 #include <hndnand.h>
35 #endif /* NFLASH_SUPPORT */
36 #ifdef _CFE_
37 #include <hndsflash.h>
38 #else
40 #endif
42 struct nvram_tuple *_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value);
43 void _nvram_free(struct nvram_tuple *t);
44 int _nvram_read(void *buf, int idx);
46 extern char *_nvram_get(const char *name);
47 extern int _nvram_set(const char *name, const char *value);
48 extern int _nvram_unset(const char *name);
49 extern int _nvram_getall(char *buf, int count);
50 extern int _nvram_commit(struct nvram_header *header);
51 extern int _nvram_init(void *si, int idx);
52 extern void _nvram_exit(void);
54 static struct nvram_header *nvram_header = NULL;
55 static int nvram_do_reset = FALSE;
57 #if defined(_CFE_) && defined(BCM_DEVINFO)
58 int _nvram_hash_sync(void);
60 char *devinfo_flashdrv_nvram = "flash0.devinfo";
62 static struct nvram_header *devinfo_nvram_header = NULL;
63 static unsigned char devinfo_nvram_nvh[MAX_NVRAM_SPACE];
64 #endif
66 #ifdef _CFE_
67 /* For NAND boot, flash0.nvram will be changed to nflash0.nvram */
68 char *flashdrv_nvram = "flash0.nvram";
69 #endif
71 #if defined(__ECOS)
72 extern int kernel_initial;
73 #define NVRAM_LOCK() cyg_scheduler_lock()
74 #define NVRAM_UNLOCK() cyg_scheduler_unlock()
75 #else
76 #define NVRAM_LOCK() do {} while (0)
77 #define NVRAM_UNLOCK() do {} while (0)
78 #endif
80 /* Convenience */
81 #define KB * 1024
82 #define MB * 1024 * 1024
84 #ifndef NVRAM_RESET_GPIO_WAIT
85 #define NVRAM_RESET_GPIO_WAIT 5000 /* in ms */
86 #endif
88 char *
89 nvram_get(const char *name)
91 char *value;
93 #ifdef __ECOS
94 if (!kernel_initial)
95 return NULL;
96 #endif
98 NVRAM_LOCK();
99 value = _nvram_get(name);
100 NVRAM_UNLOCK();
102 return value;
106 nvram_getall(char *buf, int count)
108 int ret;
110 NVRAM_LOCK();
111 ret = _nvram_getall(buf, count);
112 NVRAM_UNLOCK();
114 return ret;
118 BCMINITFN(nvram_set)(const char *name, const char *value)
120 int ret;
122 NVRAM_LOCK();
123 ret = _nvram_set(name, value);
124 NVRAM_UNLOCK();
126 return ret;
130 BCMINITFN(nvram_unset)(const char *name)
132 int ret;
134 NVRAM_LOCK();
135 ret = _nvram_unset(name);
136 NVRAM_UNLOCK();
138 return ret;
141 #define WPS_GPIO_BUTTON_VALUE "wps_button"
142 #define BCMGPIO_MAXPINS 32
144 static int
145 findmatch(const char *string, const char *name)
147 uint len;
148 char *c;
150 len = strlen(name);
151 while ((c = strchr(string, ',')) != NULL) {
152 if (len == (uint)(c - string) && !strncmp(string, name, len))
153 return 1;
154 string = c + 1;
157 return (!strcmp(string, name));
161 bcmgpio_getpin(char *pin_name)
163 char name[] = "gpioXXXX";
164 char *val;
165 uint pin;
167 /* Go thru all possibilities till a match in pin name */
168 for (pin = 0; pin < BCMGPIO_MAXPINS; pin ++) {
169 sprintf(name, "gpio%d", pin);
170 val = nvram_get(name);
171 if (val && findmatch(val, pin_name))
172 return pin;
175 return -1;
179 BCMINITFN(nvram_resetgpio_init)(void *si)
181 #if 0
182 char *value;
183 #endif
184 int gpio;
185 si_t *sih;
187 sih = (si_t *)si;
188 #if 0
189 value = nvram_get("reset_gpio");
190 if (!value)
191 return -1;
193 gpio = (int) bcm_atoi(value);
194 if (gpio > 31)
195 return -1;
196 #else
197 gpio = bcmgpio_getpin(WPS_GPIO_BUTTON_VALUE);
198 if ((gpio > 31) || (gpio < 0))
199 return -1;
200 #endif
201 /* Setup GPIO input */
202 si_gpioouten(sih, ((uint32) 1 << gpio), 0, GPIO_DRV_PRIORITY);
204 return gpio;
208 BCMINITFN(nvram_reset)(void *si)
210 int gpio;
211 uint msec;
212 si_t * sih = (si_t *)si;
214 if ((gpio = nvram_resetgpio_init((void *)sih)) < 0)
215 return FALSE;
217 /* GPIO reset is asserted low */
218 for (msec = 0; msec < NVRAM_RESET_GPIO_WAIT; msec++) {
219 if (si_gpioin(sih) & ((uint32) 1 << gpio))
220 return FALSE;
221 OSL_DELAY(1000);
224 nvram_do_reset = TRUE;
225 return TRUE;
228 #ifdef NFLASH_SUPPORT
229 static unsigned char nand_nvh[MAX_NVRAM_SPACE];
231 static struct nvram_header *
232 BCMINITFN(nand_find_nvram)(hndnand_t *nfl, uint32 off)
234 int blocksize = nfl->blocksize;
235 unsigned char *buf = nand_nvh;
236 int rlen = sizeof(nand_nvh);
237 int len;
239 for (; off < NFL_BOOT_SIZE; off += blocksize) {
240 if (hndnand_checkbadb(nfl, off) != 0)
241 continue;
243 len = blocksize;
244 if (len >= rlen)
245 len = rlen;
247 if (hndnand_read(nfl, off, len, buf) == 0)
248 break;
250 buf += len;
251 rlen -= len;
252 if (rlen == 0)
253 return (struct nvram_header *)nand_nvh;
256 return NULL;
258 #endif /* NFLASH_SUPPORT */
260 extern unsigned char embedded_nvram[];
262 static struct nvram_header *
263 BCMINITFN(find_nvram)(si_t *sih, bool embonly, bool *isemb)
265 struct nvram_header *nvh;
266 uint32 off, lim = SI_FLASH2_SZ;
267 uint32 flbase = SI_FLASH2;
268 int bootdev;
269 #ifdef NFLASH_SUPPORT
270 hndnand_t *nfl_info = NULL;
271 #endif
272 #ifdef _CFE_
273 hndsflash_t *sfl_info = NULL;
274 #endif
276 bootdev = soc_boot_dev((void *)sih);
277 #ifdef NFLASH_SUPPORT
278 if (bootdev == SOC_BOOTDEV_NANDFLASH) {
279 /* Init nand anyway */
280 nfl_info = hndnand_init(sih);
281 if (nfl_info)
282 flbase = nfl_info->phybase;
284 else
285 #endif /* NFLASH_SUPPORT */
286 if (bootdev == SOC_BOOTDEV_SFLASH) {
287 #ifdef _CFE_
288 /* Init nand anyway */
289 sfl_info = hndsflash_init(sih);
290 if (sfl_info) {
291 flbase = sfl_info->phybase;
292 lim = sfl_info->size;
294 #else
295 if (sih->ccrev == 42)
296 flbase = SI_NS_NORFLASH;
297 #endif
300 if (!embonly) {
301 *isemb = FALSE;
302 #ifdef NFLASH_SUPPORT
303 if (nfl_info) {
304 uint32 blocksize;
306 blocksize = nfl_info->blocksize;
307 off = blocksize;
308 for (; off < NFL_BOOT_SIZE; off += blocksize) {
309 if (hndnand_checkbadb(nfl_info, off) != 0)
310 continue;
311 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + off);
312 if (nvh->magic != NVRAM_MAGIC)
313 continue;
315 /* Read into the nand_nvram */
316 if ((nvh = nand_find_nvram(nfl_info, off)) == NULL)
317 continue;
318 if (nvram_calc_crc(nvh) == (uint8)nvh->crc_ver_init)
319 return nvh;
322 else
323 #endif /* NFLASH_SUPPORT */
325 off = FLASH_MIN;
326 while (off <= lim) {
327 nvh = (struct nvram_header *)
328 OSL_UNCACHED(flbase + off - MAX_NVRAM_SPACE);
329 if (nvh->magic == NVRAM_MAGIC) {
330 if (nvram_calc_crc(nvh) == (uint8) nvh->crc_ver_init) {
331 return (nvh);
334 off <<= 1;
337 #ifdef BCMDBG
338 printf("find_nvram: nvram not found, trying embedded nvram next\n");
339 #endif /* BCMDBG */
343 * Provide feedback to user when nvram corruption detected.
344 * Must be non-BCMDBG for customer release.
346 printf("Corrupt NVRAM found, trying embedded NVRAM next.\n");
348 /* Now check embedded nvram */
349 *isemb = TRUE;
350 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + (4 * 1024));
351 if (nvh->magic == NVRAM_MAGIC)
352 return (nvh);
353 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + 1024);
354 if (nvh->magic == NVRAM_MAGIC)
355 return (nvh);
356 #ifdef _CFE_
357 nvh = (struct nvram_header *)embedded_nvram;
358 if (nvh->magic == NVRAM_MAGIC)
359 return (nvh);
360 #endif
361 printf("find_nvram: no nvram found\n");
362 return (NULL);
366 BCMATTACHFN(nvram_init)(void *si)
368 bool isemb;
369 int ret;
370 si_t *sih;
371 static int nvram_status = -1;
373 #ifdef __ECOS
374 if (!kernel_initial)
375 return 0;
376 #endif
378 /* Check for previous 'restore defaults' condition */
379 if (nvram_status == 1)
380 return 1;
382 /* Check whether nvram already initilized */
383 if (nvram_status == 0 && !nvram_do_reset)
384 return 0;
386 sih = (si_t *)si;
388 /* Restore defaults from embedded NVRAM if button held down */
389 if (nvram_do_reset) {
390 /* Initialize with embedded NVRAM */
391 nvram_header = find_nvram(sih, TRUE, &isemb);
392 ret = _nvram_init(si, 0);
393 if (ret == 0) {
394 nvram_status = 1;
395 return 1;
397 nvram_status = -1;
398 _nvram_exit();
401 /* Find NVRAM */
402 nvram_header = find_nvram(sih, FALSE, &isemb);
403 ret = _nvram_init(si, 0);
404 if (ret == 0) {
405 /* Restore defaults if embedded NVRAM used */
406 if (nvram_header && isemb) {
407 ret = 1;
410 nvram_status = ret;
411 return ret;
415 BCMINITFN(nvram_append)(void *si, char *vars, uint varsz)
417 return 0;
420 void
421 BCMINITFN(nvram_exit)(void *si)
423 si_t *sih;
425 sih = (si_t *)si;
427 _nvram_exit();
430 /* LZMA need to be able to allocate memory,
431 * so set it up to use the OSL memory routines,
432 * only the linux debug osl uses the osh on malloc and the osh and size on
433 * free, and the debug code checks if they are valid, so pass NULL as the osh
434 * to tell the OSL that we don't have a valid osh
436 static void *SzAlloc(void *p, size_t size) { p = p; return MALLOC(NULL, size); }
437 static void SzFree(void *p, void *address) { p = p; MFREE(NULL, address, 0); }
438 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
441 BCMINITFN(_nvram_read)(void *buf, int idx)
443 uint32 *src, *dst;
444 uint i;
446 if (!nvram_header)
447 return -19; /* -ENODEV */
449 #if defined(_CFE_) && defined(BCM_DEVINFO)
450 if ((!devinfo_nvram_header) && (idx == 1)) {
451 return -19; /* -ENODEV */
454 src = idx == 0 ? (uint32 *) nvram_header : (uint32 *) devinfo_nvram_nvh;
455 #else
456 src = (uint32 *) nvram_header;
457 #endif
459 dst = (uint32 *) buf;
461 for (i = 0; i < sizeof(struct nvram_header); i += 4)
462 *dst++ = *src++;
464 /* Since we know what the first 3 bytes of the lzma properties
465 * should be based on what we used to compress, check them
466 * to see if we need to decompress (uncompressed this would show up a
467 * a single [ and then the end of nvram marker so its invalid in an
468 * uncompressed nvram block
470 if ((((unsigned char *)src)[0] == 0x5d) &&
471 (((unsigned char *)src)[1] == 0) &&
472 (((unsigned char *)src)[2] == 0)) {
473 unsigned int dstlen = nvram_header->len;
474 unsigned int srclen = MAX_NVRAM_SPACE-LZMA_PROPS_SIZE-NVRAM_HEADER_SIZE;
475 unsigned char *cp = (unsigned char *)src;
476 CLzmaDec state;
477 SRes res;
478 ELzmaStatus status;
480 LzmaDec_Construct(&state);
481 res = LzmaDec_Allocate(&state, cp, LZMA_PROPS_SIZE, &g_Alloc);
482 if (res != SZ_OK) {
483 printf("Error Initializing LZMA Library\n");
484 return -19;
486 LzmaDec_Init(&state);
487 res = LzmaDec_DecodeToBuf(&state,
488 (unsigned char *)dst, &dstlen,
489 &cp[LZMA_PROPS_SIZE], &srclen,
490 LZMA_FINISH_ANY,
491 &status);
493 LzmaDec_Free(&state, &g_Alloc);
494 if (res != SZ_OK) {
495 printf("Error Decompressing eNVRAM\n");
496 return -19;
498 } else {
499 for (; i < nvram_header->len && i < MAX_NVRAM_SPACE; i += 4)
500 *dst++ = ltoh32(*src++);
502 return 0;
505 struct nvram_tuple *
506 BCMINITFN(_nvram_realloc)(struct nvram_tuple *t, const char *name, const char *value)
508 if (!(t = MALLOC(NULL, sizeof(struct nvram_tuple) + strlen(name) + 1 +
509 strlen(value) + 1))) {
510 printf("_nvram_realloc: our of memory\n");
511 return NULL;
514 /* Copy name */
515 t->name = (char *) &t[1];
516 strcpy(t->name, name);
518 /* Copy value */
519 t->value = t->name + strlen(name) + 1;
520 strcpy(t->value, value);
522 return t;
525 void
526 BCMINITFN(_nvram_free)(struct nvram_tuple *t)
528 if (t)
529 MFREE(NULL, t, sizeof(struct nvram_tuple) + strlen(t->name) + 1 +
530 strlen(t->value) + 1);
533 #ifdef __ECOS
535 BCMINITFN(nvram_reinit_hash)(void)
537 struct nvram_header *header;
538 int ret;
540 if (!(header = (struct nvram_header *) MALLOC(NULL, MAX_NVRAM_SPACE))) {
541 printf("nvram_reinit_hash: out of memory\n");
542 return -12; /* -ENOMEM */
545 NVRAM_LOCK();
547 /* Regenerate NVRAM */
548 ret = _nvram_commit(header);
550 NVRAM_UNLOCK();
551 MFREE(NULL, header, MAX_NVRAM_SPACE);
552 return ret;
554 #endif /* __ECOS */
557 BCMINITFN(nvram_commit_internal)(bool nvram_corrupt)
559 struct nvram_header *header;
560 int ret;
561 uint32 *src, *dst;
562 uint i;
564 if (!(header = (struct nvram_header *) MALLOC(NULL, MAX_NVRAM_SPACE))) {
565 printf("nvram_commit: out of memory\n");
566 return -12; /* -ENOMEM */
569 NVRAM_LOCK();
571 /* Regenerate NVRAM */
572 ret = _nvram_commit(header);
573 if (ret)
574 goto done;
576 src = (uint32 *) &header[1];
577 dst = src;
579 for (i = sizeof(struct nvram_header); i < header->len && i < MAX_NVRAM_SPACE; i += 4)
580 *dst++ = htol32(*src++);
582 #ifdef _CFE_
583 if ((ret = cfe_open(flashdrv_nvram)) >= 0) {
584 if (nvram_corrupt) {
585 printf("Corrupting NVRAM...\n");
586 header->magic = NVRAM_INVALID_MAGIC;
588 cfe_writeblk(ret, 0, (unsigned char *) header, header->len);
589 cfe_close(ret);
591 #else
592 if (sysFlashInit(NULL) == 0) {
593 /* set/write invalid MAGIC # (in case writing image fails/is interrupted)
594 * write the NVRAM image to flash(with invalid magic)
595 * set/write valid MAGIC #
597 header->magic = NVRAM_CLEAR_MAGIC;
598 nvWriteChars((unsigned char *)&header->magic, sizeof(header->magic));
600 header->magic = NVRAM_INVALID_MAGIC;
601 nvWrite((unsigned short *) header, MAX_NVRAM_SPACE);
603 header->magic = NVRAM_MAGIC;
604 nvWriteChars((unsigned char *)&header->magic, sizeof(header->magic));
606 #endif /* ifdef _CFE_ */
608 done:
609 NVRAM_UNLOCK();
610 MFREE(NULL, header, MAX_NVRAM_SPACE);
611 return ret;
615 BCMINITFN(nvram_commit)(void)
617 /* do not corrupt nvram */
618 return nvram_commit_internal(FALSE);
621 #if defined(_CFE_) && defined(BCM_DEVINFO)
622 static struct nvram_header *
623 BCMINITFN(find_devinfo_nvram)(si_t *sih)
625 int cfe_fd, ret;
627 if (devinfo_nvram_header != NULL) {
628 return (devinfo_nvram_header);
631 if ((cfe_fd = cfe_open(devinfo_flashdrv_nvram)) < 0) {
632 return NULL;
635 ret = cfe_read(cfe_fd, (unsigned char *)devinfo_nvram_nvh, NVRAM_SPACE);
636 if (ret >= 0) {
637 devinfo_nvram_header = (struct nvram_header *) devinfo_nvram_nvh;
640 cfe_close(cfe_fd);
642 return (devinfo_nvram_header);
646 BCMINITFN(devinfo_nvram_init)(void *si)
648 int ret;
649 si_t *sih = (si_t *)si;
651 nvram_header = find_devinfo_nvram(sih);
652 _nvram_hash_select(1);
653 ret = _nvram_init(si, 1);
654 _nvram_hash_select(0);
656 return (ret);
659 /* sync nvram hash table with devinfo nvram hash table, and commit nvram */
661 BCMINITFN(devinfo_nvram_sync)(void)
663 _nvram_hash_sync();
664 nvram_commit();
666 return (0);
668 #endif /* _CFE_ && BCM_DEVINFO */