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(); +}  | 
