/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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))); /* 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 /* 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 * 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++); } /* 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; } char * nvram_get(const char *name) { return early_nvram_get(name); } int nvram_getall(char *buf, int count) { unsigned long flags; int ret; return early_nvram_getall(buf, count); } /* * Search the name=value vars for a specific one and return its value. * Returns NULL if not found. */ char* getvar(char *vars, const char *name) { char *s; int len; len = strlen(name); /* first look in vars[] */ for (s = vars; s && *s;) { /* CSTYLED */ if ((memcmp(s, name, len) == 0) && (s[len] == '=')) return (&s[len+1]); while (*s++); } /* then query nvram */ return (nvram_get(name)); } /* * Search the vars for a specific one and return its value as * an integer. Returns 0 if not found. */ int getintvar(char *vars, const char *name) { char *val; if ((val = getvar(vars, name)) == NULL) return (0); return (simple_strtoul(val, NULL, 0)); }