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