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