1/* 2 * NVRAM variable manipulation (common) 3 * 4 * Copyright 2007, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * 12 * $Id: nvram.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $ 13 */ 14 15#include <typedefs.h> 16#include <bcmdefs.h> 17#include <osl.h> 18#include <bcmutils.h> 19#include <sbutils.h> 20#include <bcmendian.h> 21#include <bcmnvram.h> 22#include <sbsdram.h> 23 24extern struct nvram_tuple * _nvram_realloc(struct nvram_tuple *t, const char *name, 25 const char *value); 26extern void _nvram_free(struct nvram_tuple *t); 27extern int _nvram_read(void *buf); 28 29char * _nvram_get(const char *name); 30int _nvram_set(const char *name, const char *value); 31int _nvram_unset(const char *name); 32int _nvram_getall(char *buf, int count); 33int _nvram_commit(struct nvram_header *header); 34int _nvram_init(void *sb); 35void _nvram_exit(void); 36uint8 nvram_calc_crc(struct nvram_header * nvh); 37 38static struct nvram_tuple * BCMINITDATA(nvram_hash)[257]; 39static struct nvram_tuple * nvram_dead; 40 41/* Free all tuples. Should be locked. */ 42static void 43BCMINITFN(nvram_free)(void) 44{ 45 uint i; 46 struct nvram_tuple *t, *next; 47 48 /* Free hash table */ 49 for (i = 0; i < ARRAYSIZE(nvram_hash); i++) { 50 for (t = nvram_hash[i]; t; t = next) { 51 next = t->next; 52 _nvram_free(t); 53 } 54 nvram_hash[i] = NULL; 55 } 56 57 /* Free dead table */ 58 for (t = nvram_dead; t; t = next) { 59 next = t->next; 60 _nvram_free(t); 61 } 62 nvram_dead = NULL; 63 64 /* Indicate to per-port code that all tuples have been freed */ 65 _nvram_free(NULL); 66} 67 68/* String hash */ 69static INLINE uint 70hash(const char *s) 71{ 72 uint hash = 0; 73 74 while (*s) 75 hash = 31 * hash + *s++; 76 77 return hash; 78} 79 80/* (Re)initialize the hash table. Should be locked. */ 81static int 82BCMINITFN(nvram_rehash)(struct nvram_header *header) 83{ 84 char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq; 85 86 /* (Re)initialize hash table */ 87 nvram_free(); 88 89 /* Parse and set "name=value\0 ... \0\0" */ 90 name = (char *) &header[1]; 91 end = (char *) header + NVRAM_SPACE - 2; 92 end[0] = end[1] = '\0'; 93 for (; *name; name = value + strlen(value) + 1) { 94 if (!(eq = strchr(name, '='))) 95 break; 96 *eq = '\0'; 97 value = eq + 1; 98 _nvram_set(name, value); 99 *eq = '='; 100 } 101 102 /* Set special SDRAM parameters */ 103 if (!_nvram_get("sdram_init")) { 104 sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16)); 105 _nvram_set("sdram_init", buf); 106 } 107 if (!_nvram_get("sdram_config")) { 108 sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff)); 109 _nvram_set("sdram_config", buf); 110 } 111 if (!_nvram_get("sdram_refresh")) { 112 sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff)); 113 _nvram_set("sdram_refresh", buf); 114 } 115 if (!_nvram_get("sdram_ncdl")) { 116 sprintf(buf, "0x%08X", header->config_ncdl); 117 _nvram_set("sdram_ncdl", buf); 118 } 119 120 return 0; 121} 122 123/* Get the value of an NVRAM variable. Should be locked. */ 124char * 125_nvram_get(const char *name) 126{ 127 uint i; 128 struct nvram_tuple *t; 129 char *value; 130 131 if (!name) 132 return NULL; 133 134 /* Hash the name */ 135 i = hash(name) % ARRAYSIZE(nvram_hash); 136 137 /* Find the associated tuple in the hash table */ 138 for (t = nvram_hash[i]; t && strcmp(t->name, name); t = t->next); 139 140 value = t ? t->value : NULL; 141 142 return value; 143} 144 145/* Set the value of an NVRAM variable. Should be locked. */ 146int 147BCMINITFN(_nvram_set)(const char *name, const char *value) 148{ 149 uint i; 150 struct nvram_tuple *t, *u, **prev; 151 152 /* Hash the name */ 153 i = hash(name) % ARRAYSIZE(nvram_hash); 154 155 /* Find the associated tuple in the hash table */ 156 for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); 157 prev = &t->next, t = *prev); 158 159 /* (Re)allocate tuple */ 160 if (!(u = _nvram_realloc(t, name, value))) 161 return -12; /* -ENOMEM */ 162 163 /* Value reallocated */ 164 if (t && t == u) 165 return 0; 166 167 /* Move old tuple to the dead table */ 168 if (t) { 169 *prev = t->next; 170 t->next = nvram_dead; 171 nvram_dead = t; 172 } 173 174 /* Add new tuple to the hash table */ 175 u->next = nvram_hash[i]; 176 nvram_hash[i] = u; 177 178 return 0; 179} 180 181/* Unset the value of an NVRAM variable. Should be locked. */ 182int 183BCMINITFN(_nvram_unset)(const char *name) 184{ 185 uint i; 186 struct nvram_tuple *t, **prev; 187 188 if (!name) 189 return 0; 190 191 /* Hash the name */ 192 i = hash(name) % ARRAYSIZE(nvram_hash); 193 194 /* Find the associated tuple in the hash table */ 195 for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); 196 prev = &t->next, t = *prev); 197 198 /* Move it to the dead table */ 199 if (t) { 200 *prev = t->next; 201 t->next = nvram_dead; 202 nvram_dead = t; 203 } 204 205 return 0; 206} 207 208/* Get all NVRAM variables. Should be locked. */ 209int 210_nvram_getall(char *buf, int count) 211{ 212 uint i; 213 struct nvram_tuple *t; 214 int len = 0; 215 216 bzero(buf, count); 217 218 /* Write name=value\0 ... \0\0 */ 219 for (i = 0; i < ARRAYSIZE(nvram_hash); i++) { 220 for (t = nvram_hash[i]; t; t = t->next) { 221 if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1)) 222 len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1; 223 else 224 break; 225 } 226 } 227 228 return 0; 229} 230 231/* Regenerate NVRAM. Should be locked. */ 232int 233BCMINITFN(_nvram_commit)(struct nvram_header *header) 234{ 235 char *init, *config, *refresh, *ncdl; 236 char *ptr, *end; 237 int i; 238 struct nvram_tuple *t; 239 240 /* Regenerate header */ 241 header->magic = NVRAM_MAGIC; 242 header->crc_ver_init = (NVRAM_VERSION << 8); 243 if (!(init = _nvram_get("sdram_init")) || 244 !(config = _nvram_get("sdram_config")) || 245 !(refresh = _nvram_get("sdram_refresh")) || 246 !(ncdl = _nvram_get("sdram_ncdl"))) { 247 header->crc_ver_init |= SDRAM_INIT << 16; 248 header->config_refresh = SDRAM_CONFIG; 249 header->config_refresh |= SDRAM_REFRESH << 16; 250 header->config_ncdl = 0; 251 } else { 252 header->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16; 253 header->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff; 254 header->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16; 255 header->config_ncdl = bcm_strtoul(ncdl, NULL, 0); 256 } 257 258 /* Clear data area */ 259 ptr = (char *) header + sizeof(struct nvram_header); 260 bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header)); 261 262 /* Leave space for a double NUL at the end */ 263 end = (char *) header + NVRAM_SPACE - 2; 264 265 /* Write out all tuples */ 266 for (i = 0; i < ARRAYSIZE(nvram_hash); i++) { 267 for (t = nvram_hash[i]; t; t = t->next) { 268 if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end) 269 break; 270 ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1; 271 } 272 } 273 274 /* End with a double NUL */ 275 ptr += 2; 276 277 /* Set new length */ 278 header->len = ROUNDUP(ptr - (char *) header, 4); 279 280 /* Set new CRC8 */ 281 header->crc_ver_init |= nvram_calc_crc(header); 282 283 /* Reinitialize hash table */ 284 return nvram_rehash(header); 285} 286 287/* Initialize hash table. Should be locked. */ 288int 289BCMINITFN(_nvram_init)(void *sb) 290{ 291 struct nvram_header *header; 292 int ret; 293 294 295 if (!(header = (struct nvram_header *) MALLOC(sb_osh(sb), NVRAM_SPACE))) { 296 printf("nvram_init: out of memory\n"); 297 return -12; /* -ENOMEM */ 298 } 299 300 if ((ret = _nvram_read(header)) == 0 && 301 header->magic == NVRAM_MAGIC) 302 nvram_rehash(header); 303 304 MFREE(sb_osh(sb), header, NVRAM_SPACE); 305 return ret; 306} 307 308/* Free hash table. Should be locked. */ 309void 310BCMINITFN(_nvram_exit)(void) 311{ 312 nvram_free(); 313} 314 315/* returns the CRC8 of the nvram */ 316uint8 317BCMINITFN(nvram_calc_crc)(struct nvram_header * nvh) 318{ 319 struct nvram_header tmp; 320 uint8 crc; 321 322 /* Little-endian CRC8 over the last 11 bytes of the header */ 323 tmp.crc_ver_init = htol32((nvh->crc_ver_init & NVRAM_CRC_VER_MASK)); 324 tmp.config_refresh = htol32(nvh->config_refresh); 325 tmp.config_ncdl = htol32(nvh->config_ncdl); 326 327 crc = hndcrc8((uint8 *) &tmp + NVRAM_CRC_START_POSITION, 328 sizeof(struct nvram_header) - NVRAM_CRC_START_POSITION, 329 CRC8_INIT_VALUE); 330 331 /* Continue CRC8 over data bytes */ 332 crc = hndcrc8((uint8 *) &nvh[1], nvh->len - sizeof(struct nvram_header), crc); 333 334 return crc; 335} 336