diff options
4 files changed, 153 insertions, 982 deletions
diff --git a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/Makefile b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/Makefile index f209613..e08cf9a 100644 --- a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/Makefile +++ b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/Makefile @@ -9,7 +9,7 @@ O_TARGET := bcm947xx.o export-objs := export.o obj-y := prom.o setup.o time.o sbmips.o gpio.o -obj-y += nvram.o nvram_linux.o cfe_env.o hndpmu.o +obj-y += nvram.o cfe_env.o hndpmu.o obj-y += sbutils.o utils.o bcmsrom.o hndchipc.o obj-$(CONFIG_PCI) += sbpci.o pcibios.o obj-y += export.o diff --git a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/export.c b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/export.c index ff3e031..35a578a 100644 --- a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/export.c +++ b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/export.c @@ -69,9 +69,6 @@ _export(getintvar) _export(nvram_get) _export(nvram_getall) -_export(nvram_set) -_export(nvram_unset) -_export(nvram_commit) _export(srom_read) _export(srom_write) diff --git a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/nvram.c b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/nvram.c index c37023b..e93752a 100644 --- a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/nvram.c +++ b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/nvram.c @@ -1,7 +1,7 @@ /* - * NVRAM variable manipulation (common) + * NVRAM variable manipulation (Linux kernel half) * - * Copyright 2004, Broadcom Corporation + * Copyright 2006, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY @@ -11,306 +11,203 @@ * */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/bootmem.h> +#include <linux/wrapper.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/mtd/mtd.h> +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/uaccess.h> + #include <typedefs.h> #include <osl.h> #include <bcmendian.h> #include <bcmnvram.h> -#include <sbsdram.h> - -extern struct nvram_tuple * BCMINIT(_nvram_realloc)(struct nvram_tuple *t, const char *name, const char *value); -extern void BCMINIT(_nvram_free)(struct nvram_tuple *t); -extern int BCMINIT(_nvram_read)(void *buf); - -char * BCMINIT(_nvram_get)(const char *name); -int BCMINIT(_nvram_set)(const char *name, const char *value); -int BCMINIT(_nvram_unset)(const char *name); -int BCMINIT(_nvram_getall)(char *buf, int count); -int BCMINIT(_nvram_commit)(struct nvram_header *header); -int BCMINIT(_nvram_init)(void); -void BCMINIT(_nvram_exit)(void); - -static struct nvram_tuple * BCMINITDATA(nvram_hash)[257]; -static struct nvram_tuple * nvram_dead; - -/* Free all tuples. Should be locked. */ -static void -BCMINITFN(nvram_free)(void) -{ - uint i; - struct nvram_tuple *t, *next; - - /* Free hash table */ - for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) { - for (t = BCMINIT(nvram_hash)[i]; t; t = next) { - next = t->next; - BCMINIT(_nvram_free)(t); - } - BCMINIT(nvram_hash)[i] = NULL; - } +#include <sbconfig.h> +#include <sbchipc.h> +#include <sbutils.h> +#include <hndmips.h> +#include <sflash.h> - /* Free dead table */ - for (t = nvram_dead; t; t = next) { - next = t->next; - BCMINIT(_nvram_free)(t); - } - nvram_dead = NULL; +/* In BSS to minimize text size and page aligned so it can be mmap()-ed */ +static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE))); - /* Indicate to per-port code that all tuples have been freed */ - BCMINIT(_nvram_free)(NULL); -} +/* Global SB handle */ +extern void *bcm947xx_sbh; +extern spinlock_t bcm947xx_sbh_lock; -/* String hash */ -static INLINE uint -hash(const char *s) -{ - uint hash = 0; - - while (*s) - hash = 31 * hash + *s++; +static int cfe_env; +extern char *cfe_env_get(char *nv_buf, const char *name); - return hash; -} +/* Convenience */ +#define sbh bcm947xx_sbh +#define sbh_lock bcm947xx_sbh_lock -/* (Re)initialize the hash table. Should be locked. */ -static int -BCMINITFN(nvram_rehash)(struct nvram_header *header) +/* Probe for NVRAM header */ +static void __init +early_nvram_init(void) { - char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq; - - /* (Re)initialize hash table */ - BCMINIT(nvram_free)(); + struct nvram_header *header; + chipcregs_t *cc; + struct sflash *info = NULL; + int i; + uint32 base, off, lim; + u32 *src, *dst; + + if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) { + base = KSEG1ADDR(SB_FLASH2); + switch (readl(&cc->capabilities) & CC_CAP_FLASH_MASK) { + case PFLASH: + lim = SB_FLASH2_SZ; + break; - /* 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, '='))) + case SFLASH_ST: + case SFLASH_AT: + if ((info = sflash_init(sbh,cc)) == NULL) + return; + lim = info->size; break; - *eq = '\0'; - value = eq + 1; - BCMINIT(_nvram_set)(name, value); - *eq = '='; - } - /* Set special SDRAM parameters */ - if (!BCMINIT(_nvram_get)("sdram_init")) { - sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16)); - BCMINIT(_nvram_set)("sdram_init", buf); - } - if (!BCMINIT(_nvram_get)("sdram_config")) { - sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff)); - BCMINIT(_nvram_set)("sdram_config", buf); - } - if (!BCMINIT(_nvram_get)("sdram_refresh")) { - sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff)); - BCMINIT(_nvram_set)("sdram_refresh", buf); - } - if (!BCMINIT(_nvram_get)("sdram_ncdl")) { - sprintf(buf, "0x%08X", header->config_ncdl); - BCMINIT(_nvram_set)("sdram_ncdl", buf); + case FLASH_NONE: + default: + return; + } + } else { + /* extif assumed, Stop at 4 MB */ + base = KSEG1ADDR(SB_FLASH1); + lim = SB_FLASH1_SZ; } - return 0; -} - -/* Get the value of an NVRAM variable. Should be locked. */ -char * -BCMINITFN(_nvram_get)(const char *name) -{ - uint i; - struct nvram_tuple *t; - char *value; - - if (!name) - return NULL; - - /* Hash the name */ - i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash)); - - /* Find the associated tuple in the hash table */ - for (t = BCMINIT(nvram_hash)[i]; t && strcmp(t->name, name); t = t->next); - - value = t ? t->value : NULL; + /* XXX: hack for supporting the CFE environment stuff on WGT634U */ + src = (u32 *) KSEG1ADDR(base + 8 * 1024 * 1024 - 0x2000); + dst = (u32 *) nvram_buf; + if ((lim == 0x02000000) && ((*src & 0xff00ff) == 0x000001)) { + printk("early_nvram_init: WGT634U NVRAM found.\n"); - return value; -} - -/* Get the value of an NVRAM variable. Should be locked. */ -int -BCMINITFN(_nvram_set)(const char *name, const char *value) -{ - uint i; - struct nvram_tuple *t, *u, **prev; - - /* Hash the name */ - i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash)); - - /* Find the associated tuple in the hash table */ - for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev); - - /* (Re)allocate tuple */ - if (!(u = BCMINIT(_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; + for (i = 0; i < 0x1ff0; i++) { + if (*src == 0xFFFFFFFF) + break; + *dst++ = *src++; + } + cfe_env = 1; + return; } - /* Add new tuple to the hash table */ - u->next = BCMINIT(nvram_hash)[i]; - BCMINIT(nvram_hash)[i] = u; + off = FLASH_MIN; + while (off <= lim) { + /* Windowed flash access */ + header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE); + if (header->magic == NVRAM_MAGIC) + goto found; + off <<= 1; + } - return 0; + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ + header = (struct nvram_header *) KSEG1ADDR(base + 4 * 1024); + if (header->magic == NVRAM_MAGIC) + goto found; + + header = (struct nvram_header *) KSEG1ADDR(base + 1 * 1024); + if (header->magic == NVRAM_MAGIC) + goto found; + + printk("early_nvram_init: NVRAM not found\n"); + return; + +found: + src = (u32 *) header; + dst = (u32 *) nvram_buf; + for (i = 0; i < sizeof(struct nvram_header); i += 4) + *dst++ = *src++; + for (; i < header->len && i < NVRAM_SPACE; i += 4) + *dst++ = ltoh32(*src++); } -/* Unset the value of an NVRAM variable. Should be locked. */ -int -BCMINITFN(_nvram_unset)(const char *name) +/* Early (before mm or mtd) read-only access to NVRAM */ +static char * __init +early_nvram_get(const char *name) { - uint i; - struct nvram_tuple *t, **prev; + char *var, *value, *end, *eq; if (!name) - return 0; + return NULL; + + /* Too early? */ + if (sbh == NULL) + return NULL; - /* Hash the name */ - i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash)); + if (!nvram_buf[0]) + early_nvram_init(); - /* Find the associated tuple in the hash table */ - for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev); + if (cfe_env) + return cfe_env_get(nvram_buf, name); - /* Move it to the dead table */ - if (t) { - *prev = t->next; - t->next = nvram_dead; - nvram_dead = t; + /* Look for name=value and return value */ + var = &nvram_buf[sizeof(struct nvram_header)]; + end = nvram_buf + sizeof(nvram_buf) - 2; + end[0] = end[1] = '\0'; + for (; *var; var = value + strlen(value) + 1) { + if (!(eq = strchr(var, '='))) + break; + value = eq + 1; + if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0) + return value; } - return 0; + return NULL; } -/* Get all NVRAM variables. Should be locked. */ -int -BCMINITFN(_nvram_getall)(char *buf, int count) +static int __init +early_nvram_getall(char *buf, int count) { - uint i; - struct nvram_tuple *t; + char *var, *end; int len = 0; + + /* Too early? */ + if (sbh == NULL) + return -1; + + if (!nvram_buf[0]) + early_nvram_init(); bzero(buf, count); /* Write name=value\0 ... \0\0 */ - for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) { - for (t = BCMINIT(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; - } + var = &nvram_buf[sizeof(struct nvram_header)]; + end = nvram_buf + sizeof(nvram_buf) - 2; + end[0] = end[1] = '\0'; + for (; *var; var += strlen(var) + 1) { + if ((count - len) <= (strlen(var) + 1)) + break; + len += sprintf(buf + len, "%s", var) + 1; } return 0; } -/* Regenerate NVRAM. Should be locked. */ -int -BCMINITFN(_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 = BCMINIT(_nvram_get)("sdram_init")) || - !(config = BCMINIT(_nvram_get)("sdram_config")) || - !(refresh = BCMINIT(_nvram_get)("sdram_refresh")) || - !(ncdl = BCMINIT(_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 |= (simple_strtoul(init, NULL, 0) & 0xffff) << 16; - header->config_refresh = simple_strtoul(config, NULL, 0) & 0xffff; - header->config_refresh |= (simple_strtoul(refresh, NULL, 0) & 0xffff) << 16; - header->config_ncdl = simple_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(BCMINIT(nvram_hash)); i++) { - for (t = BCMINIT(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 = hndcrc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, 0xff); - - /* Continue CRC8 over data bytes */ - crc = hndcrc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc); - - /* Set new CRC8 */ - header->crc_ver_init |= crc; - - /* Reinitialize hash table */ - return BCMINIT(nvram_rehash)(header); +char * +nvram_get(const char *name) +{ + return early_nvram_get(name); } -/* Initialize hash table. Should be locked. */ -int -BCMINITFN(_nvram_init)(void) +int +nvram_getall(char *buf, int count) { - struct nvram_header *header; + unsigned long flags; int ret; - if (!(header = (struct nvram_header *) kmalloc(NVRAM_SPACE, GFP_ATOMIC))) { - return -12; /* -ENOMEM */ - } - - if ((ret = BCMINIT(_nvram_read)(header)) == 0 && - header->magic == NVRAM_MAGIC) - BCMINIT(nvram_rehash)(header); - - kfree(header); - return ret; -} - -/* Free hash table. Should be locked. */ -void -BCMINITFN(_nvram_exit)(void) -{ - BCMINIT(nvram_free)(); + return early_nvram_getall(buf, count); } /* @@ -331,8 +228,7 @@ getvar(char *vars, const char *name) if ((memcmp(s, name, len) == 0) && (s[len] == '=')) return (&s[len+1]); - while (*s++) - ; + while (*s++); } /* then query nvram */ @@ -354,4 +250,3 @@ getintvar(char *vars, const char *name) return (simple_strtoul(val, NULL, 0)); } - diff --git a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/nvram_linux.c b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/nvram_linux.c deleted file mode 100644 index b04815d..0000000 --- a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/nvram_linux.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * NVRAM variable manipulation (Linux kernel half) - * - * Copyright 2006, 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. - * - */ - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/slab.h> -#include <linux/bootmem.h> -#include <linux/wrapper.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/mtd/mtd.h> -#include <asm/addrspace.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -#include <typedefs.h> -#include <osl.h> -#include <bcmendian.h> -#include <bcmnvram.h> -#include <sbconfig.h> -#include <sbchipc.h> -#include <sbutils.h> -#include <hndmips.h> -#include <sflash.h> - -/* In BSS to minimize text size and page aligned so it can be mmap()-ed */ -static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE))); - -#ifdef MODULE - -#define early_nvram_get(name) nvram_get(name) - -#else /* !MODULE */ - -/* Global SB handle */ -extern void *bcm947xx_sbh; -extern spinlock_t bcm947xx_sbh_lock; - -static int cfe_env; -extern char *cfe_env_get(char *nv_buf, const char *name); - -/* Convenience */ -#define sbh bcm947xx_sbh -#define sbh_lock bcm947xx_sbh_lock -#define KB * 1024 -#define MB * 1024 * 1024 - -/* Probe for NVRAM header */ -static void __init -early_nvram_init(void) -{ - struct nvram_header *header; - chipcregs_t *cc; - struct sflash *info = NULL; - int i; - uint32 base, off, lim; - u32 *src, *dst; - - if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) { - base = KSEG1ADDR(SB_FLASH2); - switch (readl(&cc->capabilities) & CC_CAP_FLASH_MASK) { - case PFLASH: - lim = SB_FLASH2_SZ; - break; - - case SFLASH_ST: - case SFLASH_AT: - if ((info = sflash_init(sbh,cc)) == NULL) - return; - lim = info->size; - break; - - case FLASH_NONE: - default: - return; - } - } else { - /* extif assumed, Stop at 4 MB */ - base = KSEG1ADDR(SB_FLASH1); - lim = SB_FLASH1_SZ; - } - - /* XXX: hack for supporting the CFE environment stuff on WGT634U */ - src = (u32 *) KSEG1ADDR(base + 8 * 1024 * 1024 - 0x2000); - dst = (u32 *) nvram_buf; - if ((lim == 0x02000000) && ((*src & 0xff00ff) == 0x000001)) { - printk("early_nvram_init: WGT634U NVRAM found.\n"); - - for (i = 0; i < 0x1ff0; i++) { - if (*src == 0xFFFFFFFF) - break; - *dst++ = *src++; - } - cfe_env = 1; - return; - } - - off = FLASH_MIN; - while (off <= lim) { - /* Windowed flash access */ - header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE); - if (header->magic == NVRAM_MAGIC) - goto found; - off <<= 1; - } - - /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ - header = (struct nvram_header *) KSEG1ADDR(base + 4 KB); - if (header->magic == NVRAM_MAGIC) - goto found; - - header = (struct nvram_header *) KSEG1ADDR(base + 1 KB); - if (header->magic == NVRAM_MAGIC) - goto found; - - printk("early_nvram_init: NVRAM not found\n"); - return; - -found: - src = (u32 *) header; - dst = (u32 *) nvram_buf; - for (i = 0; i < sizeof(struct nvram_header); i += 4) - *dst++ = *src++; - for (; i < header->len && i < NVRAM_SPACE; i += 4) - *dst++ = ltoh32(*src++); -} - -/* Early (before mm or mtd) read-only access to NVRAM */ -static char * __init -early_nvram_get(const char *name) -{ - char *var, *value, *end, *eq; - - if (!name) - return NULL; - - /* Too early? */ - if (sbh == NULL) - return NULL; - - if (!nvram_buf[0]) - early_nvram_init(); - - if (cfe_env) - return cfe_env_get(nvram_buf, name); - - /* Look for name=value and return value */ - var = &nvram_buf[sizeof(struct nvram_header)]; - end = nvram_buf + sizeof(nvram_buf) - 2; - end[0] = end[1] = '\0'; - for (; *var; var = value + strlen(value) + 1) { - if (!(eq = strchr(var, '='))) - break; - value = eq + 1; - if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0) - return value; - } - - return NULL; -} - -static int __init -early_nvram_getall(char *buf, int count) -{ - char *var, *end; - int len = 0; - - /* Too early? */ - if (sbh == NULL) - return -1; - - if (!nvram_buf[0]) - early_nvram_init(); - - bzero(buf, count); - - /* Write name=value\0 ... \0\0 */ - var = &nvram_buf[sizeof(struct nvram_header)]; - end = nvram_buf + sizeof(nvram_buf) - 2; - end[0] = end[1] = '\0'; - for (; *var; var += strlen(var) + 1) { - if ((count - len) <= (strlen(var) + 1)) - break; - len += sprintf(buf + len, "%s", var) + 1; - } - - return 0; -} -#endif /* !MODULE */ - -extern char * _nvram_get(const char *name); -extern int _nvram_set(const char *name, const char *value); -extern int _nvram_unset(const char *name); -extern int _nvram_getall(char *buf, int count); -extern int _nvram_commit(struct nvram_header *header); -extern int _nvram_init(void *sbh); -extern void _nvram_exit(void); - -/* Globals */ -static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED; -static struct semaphore nvram_sem; -static unsigned long nvram_offset = 0; -static int nvram_major = -1; -static devfs_handle_t nvram_handle = NULL; -static struct mtd_info *nvram_mtd = NULL; - -int -_nvram_read(char *buf) -{ - struct nvram_header *header = (struct nvram_header *) buf; - size_t len; - - if (!nvram_mtd || - MTD_READ(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) || - len != NVRAM_SPACE || - header->magic != NVRAM_MAGIC) { - /* Maybe we can recover some data from early initialization */ - memcpy(buf, nvram_buf, NVRAM_SPACE); - } - - return 0; -} - -struct nvram_tuple * -_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value) -{ - if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE) - return NULL; - - if (!t) { - if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC))) - return NULL; - - /* Copy name */ - t->name = (char *) &t[1]; - strcpy(t->name, name); - - t->value = NULL; - } - - /* Copy value */ - if (!t->value || strcmp(t->value, value)) { - t->value = &nvram_buf[nvram_offset]; - strcpy(t->value, value); - nvram_offset += strlen(value) + 1; - } - - return t; -} - -void -_nvram_free(struct nvram_tuple *t) -{ - if (!t) - nvram_offset = 0; - else - kfree(t); -} - -int -nvram_set(const char *name, const char *value) -{ - unsigned long flags; - int ret; - struct nvram_header *header; - - spin_lock_irqsave(&nvram_lock, flags); - if ((ret = _nvram_set(name, value))) { - /* Consolidate space and try again */ - if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) { - if (_nvram_commit(header) == 0) - ret = _nvram_set(name, value); - kfree(header); - } - } - spin_unlock_irqrestore(&nvram_lock, flags); - - return ret; -} - -char * -real_nvram_get(const char *name) -{ - unsigned long flags; - char *value; - - spin_lock_irqsave(&nvram_lock, flags); - value = _nvram_get(name); - spin_unlock_irqrestore(&nvram_lock, flags); - - return value; -} - -char * -nvram_get(const char *name) -{ - if (nvram_major >= 0) - return real_nvram_get(name); - else - return early_nvram_get(name); -} - -int -nvram_unset(const char *name) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&nvram_lock, flags); - ret = _nvram_unset(name); - spin_unlock_irqrestore(&nvram_lock, flags); - - return ret; -} - -static void -erase_callback(struct erase_info *done) -{ - wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv; - wake_up(wait_q); -} - -int -nvram_commit(void) -{ - char *buf; - size_t erasesize, len, magic_len; - unsigned int i; - int ret; - struct nvram_header *header; - unsigned long flags; - u_int32_t offset; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; - struct erase_info erase; - u_int32_t magic_offset = 0; /* Offset for writing MAGIC # */ - - if (!nvram_mtd) { - printk("nvram_commit: NVRAM not found\n"); - return -ENODEV; - } - - if (in_interrupt()) { - printk("nvram_commit: not committing in interrupt\n"); - return -EINVAL; - } - - /* Backup sector blocks to be erased */ - erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize); - if (!(buf = kmalloc(erasesize, GFP_KERNEL))) { - printk("nvram_commit: out of memory\n"); - return -ENOMEM; - } - - down(&nvram_sem); - - if ((i = erasesize - NVRAM_SPACE) > 0) { - offset = nvram_mtd->size - erasesize; - len = 0; - ret = MTD_READ(nvram_mtd, offset, i, &len, buf); - if (ret || len != i) { - printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i); - ret = -EIO; - goto done; - } - header = (struct nvram_header *)(buf + i); - magic_offset = i + ((void *)&header->magic - (void *)header); - } else { - offset = nvram_mtd->size - NVRAM_SPACE; - magic_offset = ((void *)&header->magic - (void *)header); - header = (struct nvram_header *)buf; - } - - /* clear the existing magic # to mark the NVRAM as unusable - we can pull MAGIC bits low without erase */ - header->magic = NVRAM_CLEAR_MAGIC; /* All zeros magic */ - - /* Unlock sector blocks (for Intel 28F320C3B flash) , 20060309 */ - if(nvram_mtd->unlock) - nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize); - - ret = MTD_WRITE(nvram_mtd, offset + magic_offset, sizeof(header->magic), - &magic_len, (char *)&header->magic); - if (ret || magic_len != sizeof(header->magic)) { - printk("nvram_commit: clear MAGIC error\n"); - ret = -EIO; - goto done; - } - - header->magic = NVRAM_MAGIC; /* reset MAGIC before we regenerate the NVRAM, - otherwise we'll have an incorrect CRC */ - /* Regenerate NVRAM */ - spin_lock_irqsave(&nvram_lock, flags); - ret = _nvram_commit(header); - spin_unlock_irqrestore(&nvram_lock, flags); - if (ret) - goto done; - - /* Erase sector blocks */ - init_waitqueue_head(&wait_q); - for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len; offset += nvram_mtd->erasesize) { - erase.mtd = nvram_mtd; - erase.addr = offset; - erase.len = nvram_mtd->erasesize; - erase.callback = erase_callback; - erase.priv = (u_long) &wait_q; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); - - /* Unlock sector blocks */ - if (nvram_mtd->unlock) - nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize); - - if ((ret = MTD_ERASE(nvram_mtd, &erase))) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); - printk("nvram_commit: erase error\n"); - goto done; - } - - /* Wait for erase to finish */ - schedule(); - remove_wait_queue(&wait_q, &wait); - } - - /* Write partition up to end of data area */ - header->magic = NVRAM_INVALID_MAGIC; /* All ones magic */ - offset = nvram_mtd->size - erasesize; - i = erasesize - NVRAM_SPACE + header->len; - ret = MTD_WRITE(nvram_mtd, offset, i, &len, buf); - if (ret || len != i) { - printk("nvram_commit: write error\n"); - ret = -EIO; - goto done; - } - - /* Now mark the NVRAM in flash as "valid" by setting the correct - MAGIC # */ - header->magic = NVRAM_MAGIC; - ret = MTD_WRITE(nvram_mtd, offset + magic_offset, sizeof(header->magic), - &magic_len, (char *)&header->magic); - if (ret || magic_len != sizeof(header->magic)) { - printk("nvram_commit: write MAGIC error\n"); - ret = -EIO; - goto done; - } - - /* - * Reading a few bytes back here will put the device - * back to the correct mode on certain flashes */ - offset = nvram_mtd->size - erasesize; - ret = MTD_READ(nvram_mtd, offset, 4, &len, buf); - - done: - up(&nvram_sem); - kfree(buf); - - return ret; -} - -int -nvram_getall(char *buf, int count) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&nvram_lock, flags); - if (nvram_major >= 0) - ret = _nvram_getall(buf, count); - else - ret = early_nvram_getall(buf, count); - spin_unlock_irqrestore(&nvram_lock, flags); - - return ret; -} - - - - - - - -/* User mode interface below */ - -static ssize_t -dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - char tmp[100], *name = tmp, *value; - ssize_t ret; - unsigned long off; - - if (count > sizeof(tmp)) { - if (!(name = kmalloc(count, GFP_KERNEL))) - return -ENOMEM; - } - - if (copy_from_user(name, buf, count)) { - ret = -EFAULT; - goto done; - } - - if (*name == '\0') { - /* Get all variables */ - ret = nvram_getall(name, count); - if (ret == 0) { - if (copy_to_user(buf, name, count)) { - ret = -EFAULT; - goto done; - } - ret = count; - } - } else { - if (!(value = nvram_get(name))) { - ret = 0; - goto done; - } - - /* Provide the offset into mmap() space */ - off = (unsigned long) value - (unsigned long) nvram_buf; - - if (put_user(off, (unsigned long *) buf)) { - ret = -EFAULT; - goto done; - } - - ret = sizeof(unsigned long); - } - - flush_cache_all(); - -done: - if (name != tmp) - kfree(name); - - return ret; -} - -static ssize_t -dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - char tmp[100], *name = tmp, *value; - ssize_t ret; - - if (count > sizeof(tmp)) { - if (!(name = kmalloc(count, GFP_KERNEL))) - return -ENOMEM; - } - - if (copy_from_user(name, buf, count)) { - ret = -EFAULT; - goto done; - } - - value = name; - name = strsep(&value, "="); - if (value) - ret = nvram_set(name, value) ? : count; - else - ret = nvram_unset(name) ? : count; - - done: - if (name != tmp) - kfree(name); - - return ret; -} - -static int -dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - if (cmd != NVRAM_MAGIC) - return -EINVAL; - - return nvram_commit(); -} - -static int -dev_nvram_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned long offset = virt_to_phys(nvram_buf); - - if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - return 0; -} - -static int -dev_nvram_open(struct inode *inode, struct file * file) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int -dev_nvram_release(struct inode *inode, struct file * file) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -static struct file_operations dev_nvram_fops = { - owner: THIS_MODULE, - open: dev_nvram_open, - release: dev_nvram_release, - read: dev_nvram_read, - write: dev_nvram_write, - ioctl: dev_nvram_ioctl, - mmap: dev_nvram_mmap, -}; - -static void -dev_nvram_exit(void) -{ - int order = 0; - struct page *page, *end; - - if (nvram_handle) - devfs_unregister(nvram_handle); - - if (nvram_major >= 0) - devfs_unregister_chrdev(nvram_major, "nvram"); - - if (nvram_mtd) - put_mtd_device(nvram_mtd); - - while ((PAGE_SIZE << order) < NVRAM_SPACE) - order++; - end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(nvram_buf); page <= end; page++) - mem_map_unreserve(page); - - _nvram_exit(); -} - -static int __init -dev_nvram_init(void) -{ - int order = 0, ret = 0; - struct page *page, *end; - unsigned int i; - - /* Allocate and reserve memory to mmap() */ - while ((PAGE_SIZE << order) < NVRAM_SPACE) - order++; - end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(nvram_buf); page <= end; page++) - mem_map_reserve(page); - -#ifdef CONFIG_MTD - /* Find associated MTD device */ - for (i = 0; i < MAX_MTD_DEVICES; i++) { - nvram_mtd = get_mtd_device(NULL, i); - if (nvram_mtd) { - if (!strcmp(nvram_mtd->name, "nvram") && - nvram_mtd->size >= NVRAM_SPACE) - break; - put_mtd_device(nvram_mtd); - } - } - if (i >= MAX_MTD_DEVICES) - nvram_mtd = NULL; -#endif - - /* Initialize hash table lock */ - spin_lock_init(&nvram_lock); - - /* Initialize commit semaphore */ - init_MUTEX(&nvram_sem); - - /* Register char device */ - if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) { - ret = nvram_major; - goto err; - } - - /* Initialize hash table */ - _nvram_init(sbh); - - /* Create /dev/nvram handle */ - nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL); - - /* Set the SDRAM NCDL value into NVRAM if not already done */ - if (getintvar(NULL, "sdram_ncdl") == 0) { - unsigned int ncdl; - char buf[] = "0x00000000"; - - if ((ncdl = sb_memc_get_ncdl(sbh))) { - sprintf(buf, "0x%08x", ncdl); - nvram_set("sdram_ncdl", buf); - nvram_commit(); - } - } - - return 0; - - err: - dev_nvram_exit(); - return ret; -} - -module_init(dev_nvram_init); -module_exit(dev_nvram_exit); |