diff options
Diffstat (limited to 'package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c')
-rw-r--r-- | package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c new file mode 100644 index 000000000..af12ced3f --- /dev/null +++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c @@ -0,0 +1,317 @@ +/* + * NVRAM variable manipulation (common) + * + * Copyright 2004, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id$ + */ + +#include <typedefs.h> +#include <osl.h> +#include <bcmendian.h> +#include <bcmnvram.h> +#include <bcmutils.h> +#include <sbsdram.h> + +extern struct nvram_tuple * _nvram_realloc(struct nvram_tuple *t, const char *name, const char *value); +extern void _nvram_free(struct nvram_tuple *t); +extern int _nvram_read(void *buf); + +char * _nvram_get(const char *name); +int _nvram_set(const char *name, const char *value); +int _nvram_unset(const char *name); +int _nvram_getall(char *buf, int count); +int _nvram_commit(struct nvram_header *header); +int _nvram_init(void); +void _nvram_exit(void); + +static struct nvram_tuple * nvram_hash[257]; +static struct nvram_tuple * nvram_dead; + +/* Free all tuples. Should be locked. */ +static void +nvram_free(void) +{ + uint i; + struct nvram_tuple *t, *next; + + /* Free hash table */ + for (i = 0; i < ARRAYSIZE(nvram_hash); i++) { + for (t = nvram_hash[i]; t; t = next) { + next = t->next; + _nvram_free(t); + } + nvram_hash[i] = NULL; + } + + /* Free dead table */ + for (t = nvram_dead; t; t = next) { + next = t->next; + _nvram_free(t); + } + nvram_dead = NULL; + + /* Indicate to per-port code that all tuples have been freed */ + _nvram_free(NULL); +} + +/* String hash */ +static INLINE uint +hash(const char *s) +{ + uint hash = 0; + + while (*s) + hash = 31 * hash + *s++; + + return hash; +} + +/* (Re)initialize the hash table. Should be locked. */ +static int +nvram_rehash(struct nvram_header *header) +{ + char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq; + + /* (Re)initialize hash table */ + nvram_free(); + + /* Parse and set "name=value\0 ... \0\0" */ + name = (char *) &header[1]; + end = (char *) header + NVRAM_SPACE - 2; + end[0] = end[1] = '\0'; + for (; *name; name = value + strlen(value) + 1) { + if (!(eq = strchr(name, '='))) + break; + *eq = '\0'; + value = eq + 1; + _nvram_set(name, value); + *eq = '='; + } + + /* Set special SDRAM parameters */ + if (!_nvram_get("sdram_init")) { + sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16)); + _nvram_set("sdram_init", buf); + } + if (!_nvram_get("sdram_config")) { + sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff)); + _nvram_set("sdram_config", buf); + } + if (!_nvram_get("sdram_refresh")) { + sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff)); + _nvram_set("sdram_refresh", buf); + } + if (!_nvram_get("sdram_ncdl")) { + sprintf(buf, "0x%08X", header->config_ncdl); + _nvram_set("sdram_ncdl", buf); + } + + return 0; +} + +/* Get the value of an NVRAM variable. Should be locked. */ +char * +_nvram_get(const char *name) +{ + uint i; + struct nvram_tuple *t; + char *value; + + if (!name) + return NULL; + + /* Hash the name */ + i = hash(name) % ARRAYSIZE(nvram_hash); + + /* Find the associated tuple in the hash table */ + for (t = nvram_hash[i]; t && strcmp(t->name, name); t = t->next); + + value = t ? t->value : NULL; + + return value; +} + +/* Get the value of an NVRAM variable. Should be locked. */ +int +_nvram_set(const char *name, const char *value) +{ + uint i; + struct nvram_tuple *t, *u, **prev; + + /* Hash the name */ + i = hash(name) % ARRAYSIZE(nvram_hash); + + /* Find the associated tuple in the hash table */ + for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev); + + /* (Re)allocate tuple */ + if (!(u = _nvram_realloc(t, name, value))) + return -12; /* -ENOMEM */ + + /* Value reallocated */ + if (t && t == u) + return 0; + + /* Move old tuple to the dead table */ + if (t) { + *prev = t->next; + t->next = nvram_dead; + nvram_dead = t; + } + + /* Add new tuple to the hash table */ + u->next = nvram_hash[i]; + nvram_hash[i] = u; + + return 0; +} + +/* Unset the value of an NVRAM variable. Should be locked. */ +int +_nvram_unset(const char *name) +{ + uint i; + struct nvram_tuple *t, **prev; + + if (!name) + return 0; + + /* Hash the name */ + i = hash(name) % ARRAYSIZE(nvram_hash); + + /* Find the associated tuple in the hash table */ + for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev); + + /* Move it to the dead table */ + if (t) { + *prev = t->next; + t->next = nvram_dead; + nvram_dead = t; + } + + return 0; +} + +/* Get all NVRAM variables. Should be locked. */ +int +_nvram_getall(char *buf, int count) +{ + uint i; + struct nvram_tuple *t; + int len = 0; + + bzero(buf, count); + + /* Write name=value\0 ... \0\0 */ + for (i = 0; i < ARRAYSIZE(nvram_hash); i++) { + for (t = nvram_hash[i]; t; t = t->next) { + if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1)) + len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1; + else + break; + } + } + + return 0; +} + +/* Regenerate NVRAM. Should be locked. */ +int +_nvram_commit(struct nvram_header *header) +{ + char *init, *config, *refresh, *ncdl; + char *ptr, *end; + int i; + struct nvram_tuple *t; + struct nvram_header tmp; + uint8 crc; + + /* Regenerate header */ + header->magic = NVRAM_MAGIC; + header->crc_ver_init = (NVRAM_VERSION << 8); + if (!(init = _nvram_get("sdram_init")) || + !(config = _nvram_get("sdram_config")) || + !(refresh = _nvram_get("sdram_refresh")) || + !(ncdl = _nvram_get("sdram_ncdl"))) { + header->crc_ver_init |= SDRAM_INIT << 16; + header->config_refresh = SDRAM_CONFIG; + header->config_refresh |= SDRAM_REFRESH << 16; + header->config_ncdl = 0; + } else { + header->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16; + header->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff; + header->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16; + header->config_ncdl = bcm_strtoul(ncdl, NULL, 0); + } + + /* Clear data area */ + ptr = (char *) header + sizeof(struct nvram_header); + bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header)); + + /* Leave space for a double NUL at the end */ + end = (char *) header + NVRAM_SPACE - 2; + + /* Write out all tuples */ + for (i = 0; i < ARRAYSIZE(nvram_hash); i++) { + for (t = nvram_hash[i]; t; t = t->next) { + if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end) + break; + ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1; + } + } + + /* End with a double NUL */ + ptr += 2; + + /* Set new length */ + header->len = ROUNDUP(ptr - (char *) header, 4); + + /* Little-endian CRC8 over the last 11 bytes of the header */ + tmp.crc_ver_init = htol32(header->crc_ver_init); + tmp.config_refresh = htol32(header->config_refresh); + tmp.config_ncdl = htol32(header->config_ncdl); + crc = crc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE); + + /* Continue CRC8 over data bytes */ + crc = crc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc); + + /* Set new CRC8 */ + header->crc_ver_init |= crc; + + /* Reinitialize hash table */ + return nvram_rehash(header); +} + +/* Initialize hash table. Should be locked. */ +int +_nvram_init(void) +{ + struct nvram_header *header; + int ret; + + if (!(header = (struct nvram_header *) MALLOC(NVRAM_SPACE))) { + printf("nvram_init: out of memory\n"); + return -12; /* -ENOMEM */ + } + + if ((ret = _nvram_read(header)) == 0 && + header->magic == NVRAM_MAGIC) + nvram_rehash(header); + + MFREE(header, NVRAM_SPACE); + return ret; +} + +/* Free hash table. Should be locked. */ +void +_nvram_exit(void) +{ + nvram_free(); +} |