/* * BCM947xx nvram variable access * * Copyright (C) 2005 Broadcom Corporation * Copyright (C) 2006 Felix Fietkau * Copyright (C) 2010-2011 Hauke Mehrtens * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ #include #include #include #include #include #include #include #include #include static char nvram_buf[NVRAM_SPACE]; static void nvram_find_and_copy(u32 base, u32 lim) { struct nvram_header *header; int i; u32 off; u32 *src, *dst; off = FLASH_MIN; while (off <= lim) { /* Windowed flash access */ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE); if (header->magic == NVRAM_HEADER) goto found; off <<= 1; } /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ header = (struct nvram_header *) KSEG1ADDR(base + 4096); if (header->magic == NVRAM_HEADER) goto found; header = (struct nvram_header *) KSEG1ADDR(base + 1024); if (header->magic == NVRAM_HEADER) goto found; 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++ = le32_to_cpu(*src++); } #ifdef CONFIG_BCM47XX_SSB static void nvram_init_ssb(void) { struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore; u32 base; u32 lim; if (mcore->pflash.present) { base = mcore->pflash.window; lim = mcore->pflash.window_size; } else { pr_err("Couldn't find supported flash memory\n"); return; } nvram_find_and_copy(base, lim); } #endif #ifdef CONFIG_BCM47XX_BCMA static void nvram_init_bcma(void) { struct bcma_drv_cc *cc = &bcm47xx_bus.bcma.bus.drv_cc; u32 base; u32 lim; if (cc->pflash.present) { base = cc->pflash.window; lim = cc->pflash.window_size; #ifdef CONFIG_BCMA_SFLASH } else if (cc->sflash.present) { base = cc->sflash.window; lim = cc->sflash.size; #endif } else { pr_err("Couldn't find supported flash memory\n"); return; } nvram_find_and_copy(base, lim); } #endif static void early_nvram_init(void) { switch (bcm47xx_bus_type) { #ifdef CONFIG_BCM47XX_SSB case BCM47XX_BUS_TYPE_SSB: nvram_init_ssb(); break; #endif #ifdef CONFIG_BCM47XX_BCMA case BCM47XX_BUS_TYPE_BCMA: nvram_init_bcma(); break; #endif } } int nvram_getenv(char *name, char *val, size_t val_len) { char *var, *value, *end, *eq; if (!name) return -EINVAL; if (!nvram_buf[0]) early_nvram_init(); /* 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) { eq = strchr(var, '='); if (!eq) break; value = eq + 1; if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0) { return snprintf(val, val_len, "%s", value); } } return -ENOENT; } EXPORT_SYMBOL(nvram_getenv);