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