1/* 2 * NVRAM variable manipulation (direct mapped flash) 3 * 4 * Copyright (C) 2013, 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. 17 * 18 * $Id: nvram_rw.c 258972 2011-05-11 08:57:26Z $ 19 */ 20 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 39 40#endif 41 42struct nvram_tuple *_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value); 43void _nvram_free(struct nvram_tuple *t); 44int _nvram_read(void *buf, int idx); 45 46extern char *_nvram_get(const char *name); 47extern int _nvram_set(const char *name, const char *value); 48extern int _nvram_unset(const char *name); 49extern int _nvram_getall(char *buf, int count); 50extern int _nvram_commit(struct nvram_header *header); 51extern int _nvram_init(void *si, int idx); 52extern void _nvram_exit(void); 53 54static struct nvram_header *nvram_header = NULL; 55static int nvram_do_reset = FALSE; 56 57#if defined(_CFE_) && defined(BCM_DEVINFO) 58int _nvram_hash_sync(void); 59 60char *devinfo_flashdrv_nvram = "flash0.devinfo"; 61 62static struct nvram_header *devinfo_nvram_header = NULL; 63static unsigned char devinfo_nvram_nvh[MAX_NVRAM_SPACE]; 64#endif 65 66#ifdef _CFE_ 67/* For NAND boot, flash0.nvram will be changed to nflash0.nvram */ 68char *flashdrv_nvram = "flash0.nvram"; 69#endif 70 71#if defined(__ECOS) 72extern 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 79 80/* Convenience */ 81#define KB * 1024 82#define MB * 1024 * 1024 83 84#ifndef NVRAM_RESET_GPIO_WAIT 85#define NVRAM_RESET_GPIO_WAIT 5000 /* in ms */ 86#endif 87 88char * 89nvram_get(const char *name) 90{ 91 char *value; 92 93#ifdef __ECOS 94 if (!kernel_initial) 95 return NULL; 96#endif 97 98 NVRAM_LOCK(); 99 value = _nvram_get(name); 100 NVRAM_UNLOCK(); 101 102 return value; 103} 104 105int 106nvram_getall(char *buf, int count) 107{ 108 int ret; 109 110 NVRAM_LOCK(); 111 ret = _nvram_getall(buf, count); 112 NVRAM_UNLOCK(); 113 114 return ret; 115} 116 117int 118BCMINITFN(nvram_set)(const char *name, const char *value) 119{ 120 int ret; 121 122 NVRAM_LOCK(); 123 ret = _nvram_set(name, value); 124 NVRAM_UNLOCK(); 125 126 return ret; 127} 128 129int 130BCMINITFN(nvram_unset)(const char *name) 131{ 132 int ret; 133 134 NVRAM_LOCK(); 135 ret = _nvram_unset(name); 136 NVRAM_UNLOCK(); 137 138 return ret; 139} 140 141int 142BCMINITFN(nvram_resetgpio_init)(void *si) 143{ 144 char *value; 145 int gpio; 146 si_t *sih; 147 148 sih = (si_t *)si; 149 150 value = nvram_get("reset_gpio"); 151 if (!value) 152 return -1; 153 154 gpio = (int) bcm_atoi(value); 155 if (gpio > 31) 156 return -1; 157 158 /* Setup GPIO input */ 159 si_gpioouten(sih, ((uint32) 1 << gpio), 0, GPIO_DRV_PRIORITY); 160 161 return gpio; 162} 163 164int 165BCMINITFN(nvram_reset)(void *si) 166{ 167 int gpio; 168 uint msec; 169 si_t * sih = (si_t *)si; 170 171 if ((gpio = nvram_resetgpio_init((void *)sih)) < 0) 172 return FALSE; 173 174 /* GPIO reset is asserted low */ 175 for (msec = 0; msec < NVRAM_RESET_GPIO_WAIT; msec++) { 176 if (si_gpioin(sih) & ((uint32) 1 << gpio)) 177 return FALSE; 178 OSL_DELAY(1000); 179 } 180 181 nvram_do_reset = TRUE; 182 return TRUE; 183} 184 185#ifdef NFLASH_SUPPORT 186static unsigned char nand_nvh[MAX_NVRAM_SPACE]; 187 188static struct nvram_header * 189BCMINITFN(nand_find_nvram)(hndnand_t *nfl, uint32 off) 190{ 191 int blocksize = nfl->blocksize; 192 unsigned char *buf = nand_nvh; 193 int rlen = sizeof(nand_nvh); 194 int len; 195 196 for (; off < NFL_BOOT_SIZE; off += blocksize) { 197 if (hndnand_checkbadb(nfl, off) != 0) 198 continue; 199 200 len = blocksize; 201 if (len >= rlen) 202 len = rlen; 203 204 if (hndnand_read(nfl, off, len, buf) == 0) 205 break; 206 207 buf += len; 208 rlen -= len; 209 if (rlen == 0) 210 return (struct nvram_header *)nand_nvh; 211 } 212 213 return NULL; 214} 215#endif /* NFLASH_SUPPORT */ 216 217extern unsigned char embedded_nvram[]; 218 219static struct nvram_header * 220BCMINITFN(find_nvram)(si_t *sih, bool embonly, bool *isemb) 221{ 222 struct nvram_header *nvh; 223 uint32 off, lim = SI_FLASH2_SZ; 224 uint32 flbase = SI_FLASH2; 225 int bootdev; 226#ifdef NFLASH_SUPPORT 227 hndnand_t *nfl_info = NULL; 228#endif 229#ifdef _CFE_ 230 hndsflash_t *sfl_info = NULL; 231#endif 232 233 bootdev = soc_boot_dev((void *)sih); 234#ifdef NFLASH_SUPPORT 235 if (bootdev == SOC_BOOTDEV_NANDFLASH) { 236 /* Init nand anyway */ 237 nfl_info = hndnand_init(sih); 238 if (nfl_info) 239 flbase = nfl_info->phybase; 240 } 241 else 242#endif /* NFLASH_SUPPORT */ 243 if (bootdev == SOC_BOOTDEV_SFLASH) { 244#ifdef _CFE_ 245 /* Init nand anyway */ 246 sfl_info = hndsflash_init(sih); 247 if (sfl_info) { 248 flbase = sfl_info->phybase; 249 lim = sfl_info->size; 250 } 251#else 252 if (sih->ccrev == 42) 253 flbase = SI_NS_NORFLASH; 254#endif 255 } 256 257 if (!embonly) { 258 *isemb = FALSE; 259#ifdef NFLASH_SUPPORT 260 if (nfl_info) { 261 uint32 blocksize; 262 263 blocksize = nfl_info->blocksize; 264 off = blocksize; 265 for (; off < NFL_BOOT_SIZE; off += blocksize) { 266 if (hndnand_checkbadb(nfl_info, off) != 0) 267 continue; 268 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + off); 269 if (nvh->magic != NVRAM_MAGIC) 270 continue; 271 272 /* Read into the nand_nvram */ 273 if ((nvh = nand_find_nvram(nfl_info, off)) == NULL) 274 continue; 275 if (nvram_calc_crc(nvh) == (uint8)nvh->crc_ver_init) 276 return nvh; 277 } 278 } 279 else 280#endif /* NFLASH_SUPPORT */ 281 { 282 off = FLASH_MIN; 283 while (off <= lim) { 284 nvh = (struct nvram_header *) 285 OSL_UNCACHED(flbase + off - MAX_NVRAM_SPACE); 286 if (nvh->magic == NVRAM_MAGIC) { 287 if (nvram_calc_crc(nvh) == (uint8) nvh->crc_ver_init) { 288 return (nvh); 289 } 290 } 291 off <<= 1; 292 } 293 } 294 } 295 296 /* 297 * Provide feedback to user when nvram corruption detected. 298 * Must be non-BCMDBG for customer release. 299 */ 300 printf("Corrupt NVRAM found, trying embedded NVRAM next.\n"); 301 302 /* Now check embedded nvram */ 303 *isemb = TRUE; 304 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + (4 * 1024)); 305 if (nvh->magic == NVRAM_MAGIC) 306 return (nvh); 307 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + 1024); 308 if (nvh->magic == NVRAM_MAGIC) 309 return (nvh); 310#ifdef _CFE_ 311 nvh = (struct nvram_header *)embedded_nvram; 312 if (nvh->magic == NVRAM_MAGIC) 313 return (nvh); 314#endif 315 printf("find_nvram: no nvram found\n"); 316 return (NULL); 317} 318 319int 320BCMATTACHFN(nvram_init)(void *si) 321{ 322 bool isemb; 323 int ret; 324 si_t *sih; 325 static int nvram_status = -1; 326 327#ifdef __ECOS 328 if (!kernel_initial) 329 return 0; 330#endif 331 332 /* Check for previous 'restore defaults' condition */ 333 if (nvram_status == 1) 334 return 1; 335 336 /* Check whether nvram already initilized */ 337 if (nvram_status == 0 && !nvram_do_reset) 338 return 0; 339 340 sih = (si_t *)si; 341 342 /* Restore defaults from embedded NVRAM if button held down */ 343 if (nvram_do_reset) { 344 /* Initialize with embedded NVRAM */ 345 nvram_header = find_nvram(sih, TRUE, &isemb); 346 ret = _nvram_init(si, 0); 347 if (ret == 0) { 348 nvram_status = 1; 349 return 1; 350 } 351 nvram_status = -1; 352 _nvram_exit(); 353 } 354 355 /* Find NVRAM */ 356 nvram_header = find_nvram(sih, FALSE, &isemb); 357 ret = _nvram_init(si, 0); 358 if (ret == 0) { 359 /* Restore defaults if embedded NVRAM used */ 360 if (nvram_header && isemb) { 361 ret = 1; 362 } 363 } 364 nvram_status = ret; 365 return ret; 366} 367 368int 369BCMINITFN(nvram_append)(void *si, char *vars, uint varsz) 370{ 371 return 0; 372} 373 374void 375BCMINITFN(nvram_exit)(void *si) 376{ 377 si_t *sih; 378 379 sih = (si_t *)si; 380 381 _nvram_exit(); 382} 383 384/* LZMA need to be able to allocate memory, 385 * so set it up to use the OSL memory routines, 386 * only the linux debug osl uses the osh on malloc and the osh and size on 387 * free, and the debug code checks if they are valid, so pass NULL as the osh 388 * to tell the OSL that we don't have a valid osh 389 */ 390static void *SzAlloc(void *p, size_t size) { p = p; return MALLOC(NULL, size); } 391static void SzFree(void *p, void *address) { p = p; MFREE(NULL, address, 0); } 392static ISzAlloc g_Alloc = { SzAlloc, SzFree }; 393 394int 395BCMINITFN(_nvram_read)(void *buf, int idx) 396{ 397 uint32 *src, *dst; 398 uint i; 399 400 if (!nvram_header) 401 return -19; /* -ENODEV */ 402 403#if defined(_CFE_) && defined(BCM_DEVINFO) 404 if ((!devinfo_nvram_header) && (idx == 1)) { 405 return -19; /* -ENODEV */ 406 } 407 408 src = idx == 0 ? (uint32 *) nvram_header : (uint32 *) devinfo_nvram_nvh; 409#else 410 src = (uint32 *) nvram_header; 411#endif 412 413 dst = (uint32 *) buf; 414 415 for (i = 0; i < sizeof(struct nvram_header); i += 4) 416 *dst++ = *src++; 417 418 /* Since we know what the first 3 bytes of the lzma properties 419 * should be based on what we used to compress, check them 420 * to see if we need to decompress (uncompressed this would show up a 421 * a single [ and then the end of nvram marker so its invalid in an 422 * uncompressed nvram block 423 */ 424 if ((((unsigned char *)src)[0] == 0x5d) && 425 (((unsigned char *)src)[1] == 0) && 426 (((unsigned char *)src)[2] == 0)) { 427 unsigned int dstlen = nvram_header->len; 428 unsigned int srclen = MAX_NVRAM_SPACE-LZMA_PROPS_SIZE-NVRAM_HEADER_SIZE; 429 unsigned char *cp = (unsigned char *)src; 430 CLzmaDec state; 431 SRes res; 432 ELzmaStatus status; 433 434 LzmaDec_Construct(&state); 435 res = LzmaDec_Allocate(&state, cp, LZMA_PROPS_SIZE, &g_Alloc); 436 if (res != SZ_OK) { 437 printf("Error Initializing LZMA Library\n"); 438 return -19; 439 } 440 LzmaDec_Init(&state); 441 res = LzmaDec_DecodeToBuf(&state, 442 (unsigned char *)dst, &dstlen, 443 &cp[LZMA_PROPS_SIZE], &srclen, 444 LZMA_FINISH_ANY, 445 &status); 446 447 LzmaDec_Free(&state, &g_Alloc); 448 if (res != SZ_OK) { 449 printf("Error Decompressing eNVRAM\n"); 450 return -19; 451 } 452 } else { 453 for (; i < nvram_header->len && i < MAX_NVRAM_SPACE; i += 4) 454 *dst++ = ltoh32(*src++); 455 } 456 return 0; 457} 458 459struct nvram_tuple * 460BCMINITFN(_nvram_realloc)(struct nvram_tuple *t, const char *name, const char *value) 461{ 462 if (!(t = MALLOC(NULL, sizeof(struct nvram_tuple) + strlen(name) + 1 + 463 strlen(value) + 1))) { 464 printf("_nvram_realloc: our of memory\n"); 465 return NULL; 466 } 467 468 /* Copy name */ 469 t->name = (char *) &t[1]; 470 strcpy(t->name, name); 471 472 /* Copy value */ 473 t->value = t->name + strlen(name) + 1; 474 strcpy(t->value, value); 475 476 return t; 477} 478 479void 480BCMINITFN(_nvram_free)(struct nvram_tuple *t) 481{ 482 if (t) 483 MFREE(NULL, t, sizeof(struct nvram_tuple) + strlen(t->name) + 1 + 484 strlen(t->value) + 1); 485} 486 487#ifdef __ECOS 488int 489BCMINITFN(nvram_reinit_hash)(void) 490{ 491 struct nvram_header *header; 492 int ret; 493 494 if (!(header = (struct nvram_header *) MALLOC(NULL, MAX_NVRAM_SPACE))) { 495 printf("nvram_reinit_hash: out of memory\n"); 496 return -12; /* -ENOMEM */ 497 } 498 499 NVRAM_LOCK(); 500 501 /* Regenerate NVRAM */ 502 ret = _nvram_commit(header); 503 504 NVRAM_UNLOCK(); 505 MFREE(NULL, header, MAX_NVRAM_SPACE); 506 return ret; 507} 508#endif /* __ECOS */ 509 510int 511BCMINITFN(nvram_commit_internal)(bool nvram_corrupt) 512{ 513 struct nvram_header *header; 514 int ret; 515 uint32 *src, *dst; 516 uint i; 517 518 if (!(header = (struct nvram_header *) MALLOC(NULL, MAX_NVRAM_SPACE))) { 519 printf("nvram_commit: out of memory\n"); 520 return -12; /* -ENOMEM */ 521 } 522 523 NVRAM_LOCK(); 524 525 /* Regenerate NVRAM */ 526 ret = _nvram_commit(header); 527 if (ret) 528 goto done; 529 530 src = (uint32 *) &header[1]; 531 dst = src; 532 533 for (i = sizeof(struct nvram_header); i < header->len && i < MAX_NVRAM_SPACE; i += 4) 534 *dst++ = htol32(*src++); 535 536#ifdef _CFE_ 537 if ((ret = cfe_open(flashdrv_nvram)) >= 0) { 538 if (nvram_corrupt) { 539 printf("Corrupting NVRAM...\n"); 540 header->magic = NVRAM_INVALID_MAGIC; 541 } 542 cfe_writeblk(ret, 0, (unsigned char *) header, header->len); 543 cfe_close(ret); 544 } 545#else 546 if (sysFlashInit(NULL) == 0) { 547 /* set/write invalid MAGIC # (in case writing image fails/is interrupted) 548 * write the NVRAM image to flash(with invalid magic) 549 * set/write valid MAGIC # 550 */ 551 header->magic = NVRAM_CLEAR_MAGIC; 552 nvWriteChars((unsigned char *)&header->magic, sizeof(header->magic)); 553 554 header->magic = NVRAM_INVALID_MAGIC; 555 nvWrite((unsigned short *) header, MAX_NVRAM_SPACE); 556 557 header->magic = NVRAM_MAGIC; 558 nvWriteChars((unsigned char *)&header->magic, sizeof(header->magic)); 559 } 560#endif /* ifdef _CFE_ */ 561 562done: 563 NVRAM_UNLOCK(); 564 MFREE(NULL, header, MAX_NVRAM_SPACE); 565 return ret; 566} 567 568int 569BCMINITFN(nvram_commit)(void) 570{ 571 /* do not corrupt nvram */ 572 return nvram_commit_internal(FALSE); 573} 574 575#if defined(_CFE_) && defined(BCM_DEVINFO) 576static struct nvram_header * 577BCMINITFN(find_devinfo_nvram)(si_t *sih) 578{ 579 int cfe_fd, ret; 580 581 if (devinfo_nvram_header != NULL) { 582 return (devinfo_nvram_header); 583 } 584 585 if ((cfe_fd = cfe_open(devinfo_flashdrv_nvram)) < 0) { 586 return NULL; 587 } 588 589 ret = cfe_read(cfe_fd, (unsigned char *)devinfo_nvram_nvh, NVRAM_SPACE); 590 if (ret >= 0) { 591 devinfo_nvram_header = (struct nvram_header *) devinfo_nvram_nvh; 592 } 593 594 cfe_close(cfe_fd); 595 596 return (devinfo_nvram_header); 597} 598 599int 600BCMINITFN(devinfo_nvram_init)(void *si) 601{ 602 int ret; 603 si_t *sih = (si_t *)si; 604 605 nvram_header = find_devinfo_nvram(sih); 606 _nvram_hash_select(1); 607 ret = _nvram_init(si, 1); 608 _nvram_hash_select(0); 609 610 return (ret); 611} 612 613/* sync nvram hash table with devinfo nvram hash table, and commit nvram */ 614int 615BCMINITFN(devinfo_nvram_sync)(void) 616{ 617 _nvram_hash_sync(); 618 nvram_commit(); 619 620 return (0); 621} 622#endif /* _CFE_ && BCM_DEVINFO */ 623