[au1500] do not override input config symbols (#4722)
[15.05/openwrt.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