blob: 65be507f4ee3bf23838878deeac9c049509bf39d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * csr1212.c -- IEEE 1212 Control and Status Register support for Linux
3 *
4 * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
5 * Steve Kinneberg <kinnebergsteve@acmsystems.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30
31/* TODO List:
32 * - Verify interface consistency: i.e., public functions that take a size
33 * parameter expect size to be in bytes.
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 */
35
Stefan Richter7fb9add2007-03-11 22:49:05 +010036#include <linux/errno.h>
37#include <linux/string.h>
38#include <asm/byteorder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40#include "csr1212.h"
41
42
43/* Permitted key type for each key id */
44#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
45#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
46#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
47#define __L (1 << CSR1212_KV_TYPE_LEAF)
Stefan Richter982610b2007-03-11 22:49:34 +010048static const u8 csr1212_key_id_type_map[0x30] = {
Andrea Guzzo0749aaa2006-12-08 00:53:24 +010049 __C, /* used by Apple iSight */
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 __D | __L, /* Descriptor */
51 __I | __D | __L, /* Bus_Dependent_Info */
52 __I | __D | __L, /* Vendor */
53 __I, /* Hardware_Version */
54 0, 0, /* Reserved */
Andrea Guzzo0749aaa2006-12-08 00:53:24 +010055 __D | __L | __I, /* Module */
56 __I, 0, 0, 0, /* used by Apple iSight, Reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 __I, /* Node_Capabilities */
58 __L, /* EUI_64 */
59 0, 0, 0, /* Reserved */
60 __D, /* Unit */
61 __I, /* Specifier_ID */
62 __I, /* Version */
63 __I | __C | __D | __L, /* Dependent_Info */
64 __L, /* Unit_Location */
65 0, /* Reserved */
66 __I, /* Model */
67 __D, /* Instance */
68 __L, /* Keyword */
69 __D, /* Feature */
70 __L, /* Extended_ROM */
71 __I, /* Extended_Key_Specifier_ID */
72 __I, /* Extended_Key */
73 __I | __C | __D | __L, /* Extended_Data */
74 __L, /* Modifiable_Descriptor */
75 __I, /* Directory_ID */
76 __I, /* Revision */
77};
78#undef __I
79#undef __C
80#undef __D
81#undef __L
82
83
Stefan Richter982610b2007-03-11 22:49:34 +010084#define quads_to_bytes(_q) ((_q) * sizeof(u32))
85#define bytes_to_quads(_b) (((_b) + sizeof(u32) - 1) / sizeof(u32))
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Stefan Richter6c88e472007-03-11 22:47:34 +010087static void free_keyval(struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
90 (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
91 CSR1212_FREE(kv->value.leaf.data);
92
93 CSR1212_FREE(kv);
94}
95
Stefan Richter982610b2007-03-11 22:49:34 +010096static u16 csr1212_crc16(const u32 *buffer, size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097{
98 int shift;
Stefan Richter982610b2007-03-11 22:49:34 +010099 u32 data;
100 u16 sum, crc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102 for (; length; length--) {
Stefan Richter7fb9add2007-03-11 22:49:05 +0100103 data = be32_to_cpu(*buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 buffer++;
105 for (shift = 28; shift >= 0; shift -= 4 ) {
106 sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
107 crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
108 }
109 crc &= 0xffff;
110 }
111
Stefan Richter7fb9add2007-03-11 22:49:05 +0100112 return cpu_to_be16(crc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113}
114
115#if 0
116/* Microsoft computes the CRC with the bytes in reverse order. Therefore we
117 * have a special version of the CRC algorithm to account for their buggy
118 * software. */
Stefan Richter982610b2007-03-11 22:49:34 +0100119static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120{
121 int shift;
Stefan Richter982610b2007-03-11 22:49:34 +0100122 u32 data;
123 u16 sum, crc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125 for (; length; length--) {
Stefan Richter7fb9add2007-03-11 22:49:05 +0100126 data = le32_to_cpu(*buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 buffer++;
128 for (shift = 28; shift >= 0; shift -= 4 ) {
129 sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
130 crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
131 }
132 crc &= 0xffff;
133 }
134
Stefan Richter7fb9add2007-03-11 22:49:05 +0100135 return cpu_to_be16(crc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137#endif
138
Stefan Richter6c88e472007-03-11 22:47:34 +0100139static struct csr1212_dentry *
140csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
142 struct csr1212_dentry *pos;
143
144 for (pos = dir->value.directory.dentries_head;
145 pos != NULL; pos = pos->next) {
146 if (pos->kv == kv)
147 return pos;
148 }
149 return NULL;
150}
151
Stefan Richter6c88e472007-03-11 22:47:34 +0100152static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100153csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
155 struct csr1212_keyval *kv;
156
157 for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) {
158 if (kv->offset == offset)
159 return kv;
160 }
161 return NULL;
162}
163
164
165/* Creation Routines */
Stefan Richter6c88e472007-03-11 22:47:34 +0100166
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
168 size_t bus_info_size, void *private)
169{
170 struct csr1212_csr *csr;
171
172 csr = CSR1212_MALLOC(sizeof(*csr));
173 if (!csr)
174 return NULL;
175
176 csr->cache_head =
177 csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
178 CSR1212_CONFIG_ROM_SPACE_SIZE);
179 if (!csr->cache_head) {
180 CSR1212_FREE(csr);
181 return NULL;
182 }
183
184 /* The keyval key id is not used for the root node, but a valid key id
185 * that can be used for a directory needs to be passed to
186 * csr1212_new_directory(). */
187 csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
188 if (!csr->root_kv) {
189 CSR1212_FREE(csr->cache_head);
190 CSR1212_FREE(csr);
191 return NULL;
192 }
193
194 csr->bus_info_data = csr->cache_head->data;
195 csr->bus_info_len = bus_info_size;
196 csr->crc_len = bus_info_size;
197 csr->ops = ops;
198 csr->private = private;
199 csr->cache_tail = csr->cache_head;
200
201 return csr;
202}
203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204void csr1212_init_local_csr(struct csr1212_csr *csr,
Stefan Richter982610b2007-03-11 22:49:34 +0100205 const u32 *bus_info_data, int max_rom)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
207 static const int mr_map[] = { 4, 64, 1024, 0 };
208
Ben Collins1934b8b2005-07-09 20:01:23 -0400209 BUG_ON(max_rom & ~0x3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 csr->max_rom = mr_map[max_rom];
211 memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
212}
213
Stefan Richter982610b2007-03-11 22:49:34 +0100214static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
216 struct csr1212_keyval *kv;
217
218 if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
219 return NULL;
220
221 kv = CSR1212_MALLOC(sizeof(*kv));
222 if (!kv)
223 return NULL;
224
225 kv->key.type = type;
226 kv->key.id = key;
227
228 kv->associate = NULL;
229 kv->refcnt = 1;
230
231 kv->next = NULL;
232 kv->prev = NULL;
233 kv->offset = 0;
234 kv->valid = 0;
235 return kv;
236}
237
Stefan Richter982610b2007-03-11 22:49:34 +0100238struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
240 struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
241
242 if (!kv)
243 return NULL;
244
245 kv->value.immediate = value;
246 kv->valid = 1;
247 return kv;
248}
249
Stefan Richter6c88e472007-03-11 22:47:34 +0100250static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100251csr1212_new_leaf(u8 key, const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252{
253 struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
254
255 if (!kv)
256 return NULL;
257
258 if (data_len > 0) {
259 kv->value.leaf.data = CSR1212_MALLOC(data_len);
260 if (!kv->value.leaf.data) {
261 CSR1212_FREE(kv);
262 return NULL;
263 }
264
265 if (data)
266 memcpy(kv->value.leaf.data, data, data_len);
267 } else {
268 kv->value.leaf.data = NULL;
269 }
270
271 kv->value.leaf.len = bytes_to_quads(data_len);
272 kv->offset = 0;
273 kv->valid = 1;
274
275 return kv;
276}
277
Stefan Richter6c88e472007-03-11 22:47:34 +0100278static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100279csr1212_new_csr_offset(u8 key, u32 csr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280{
281 struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
282
283 if (!kv)
284 return NULL;
285
286 kv->value.csr_offset = csr_offset;
287
288 kv->offset = 0;
289 kv->valid = 1;
290 return kv;
291}
292
Stefan Richter982610b2007-03-11 22:49:34 +0100293struct csr1212_keyval *csr1212_new_directory(u8 key)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
295 struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
296
297 if (!kv)
298 return NULL;
299
300 kv->value.directory.len = 0;
301 kv->offset = 0;
302 kv->value.directory.dentries_head = NULL;
303 kv->value.directory.dentries_tail = NULL;
304 kv->valid = 1;
305 return kv;
306}
307
308int csr1212_associate_keyval(struct csr1212_keyval *kv,
309 struct csr1212_keyval *associate)
310{
311 if (!kv || !associate)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100312 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 if (kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
315 (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
316 associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
317 associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
318 associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
319 associate->key.id < 0x30))
Stefan Richter7fb9add2007-03-11 22:49:05 +0100320 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
323 associate->key.id != CSR1212_KV_ID_EXTENDED_KEY)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100324 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
327 associate->key.id != CSR1212_KV_ID_EXTENDED_DATA)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100328 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 if (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
331 kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100332 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
334 if (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
335 kv->key.id != CSR1212_KV_ID_EXTENDED_KEY)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100336 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 if (kv->associate)
339 csr1212_release_keyval(kv->associate);
340
341 associate->refcnt++;
342 kv->associate = associate;
343
344 return CSR1212_SUCCESS;
345}
346
347int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
348 struct csr1212_keyval *kv)
349{
350 struct csr1212_dentry *dentry;
351
352 if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100353 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
355 dentry = CSR1212_MALLOC(sizeof(*dentry));
356 if (!dentry)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100357 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 dentry->kv = kv;
360
361 kv->refcnt++;
362
363 dentry->next = NULL;
364 dentry->prev = dir->value.directory.dentries_tail;
365
366 if (!dir->value.directory.dentries_head)
367 dir->value.directory.dentries_head = dentry;
368
369 if (dir->value.directory.dentries_tail)
370 dir->value.directory.dentries_tail->next = dentry;
371 dir->value.directory.dentries_tail = dentry;
372
373 return CSR1212_SUCCESS;
374}
375
Stefan Richter6c88e472007-03-11 22:47:34 +0100376#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
377 (&((kv)->value.leaf.data[1]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Stefan Richter6c88e472007-03-11 22:47:34 +0100379#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
380 ((kv)->value.leaf.data[0] = \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100381 cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
382 ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
Stefan Richter6c88e472007-03-11 22:47:34 +0100383#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
384 ((kv)->value.leaf.data[0] = \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100385 cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
386 CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
387 ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Stefan Richter6c88e472007-03-11 22:47:34 +0100389static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100390csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
Stefan Richter6c88e472007-03-11 22:47:34 +0100391 const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
393 struct csr1212_keyval *kv;
394
395 kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
396 data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
397 if (!kv)
398 return NULL;
399
400 CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
401 CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
402
403 if (data) {
404 memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
405 }
406
407 return kv;
408}
409
Stefan Richter6c88e472007-03-11 22:47:34 +0100410#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \
411 ((kv)->value.leaf.data[1] = \
412 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100413 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \
414 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \
415 cpu_to_be32(((width) & CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \
416 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Stefan Richter6c88e472007-03-11 22:47:34 +0100418#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \
419 ((kv)->value.leaf.data[1] = \
420 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100421 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \
422 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \
423 cpu_to_be32(((char_set) & \
424 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \
425 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))
Stefan Richter6c88e472007-03-11 22:47:34 +0100426
427#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
428 ((kv)->value.leaf.data[1] = \
429 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100430 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
431 cpu_to_be32(((language) & \
432 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
Stefan Richter6c88e472007-03-11 22:47:34 +0100433
434static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100435csr1212_new_textual_descriptor_leaf(u8 cwidth, u16 cset, u16 language,
436 const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 struct csr1212_keyval *kv;
439 char *lstr;
440
441 kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len +
442 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
443 if (!kv)
444 return NULL;
445
446 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth);
447 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset);
448 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
449
450 lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
451
452 /* make sure last quadlet is zeroed out */
Stefan Richter982610b2007-03-11 22:49:34 +0100453 *((u32*)&(lstr[(data_len - 1) & ~0x3])) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 /* don't copy the NUL terminator */
456 memcpy(lstr, data, data_len);
457
458 return kv;
459}
460
461static int csr1212_check_minimal_ascii(const char *s)
462{
463 static const char minimal_ascii_table[] = {
464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
465 0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00,
466 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468 0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27,
469 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
470 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
471 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
472 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
473 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
474 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
475 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
476 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
477 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
478 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
479 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
480 };
481 for (; *s; s++) {
482 if (minimal_ascii_table[*s & 0x7F] != *s)
483 return -1; /* failed */
484 }
485 /* String conforms to minimal-ascii, as specified by IEEE 1212,
486 * par. 7.4 */
487 return 0;
488}
489
490struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
491{
492 /* Check if string conform to minimal_ascii format */
493 if (csr1212_check_minimal_ascii(s))
494 return NULL;
495
496 /* IEEE 1212, par. 7.5.4.1 Textual descriptors (minimal ASCII) */
497 return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s));
498}
499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
501/* Destruction Routines */
502
503void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
504 struct csr1212_keyval *kv)
505{
506 struct csr1212_dentry *dentry;
507
508 if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
509 return;
510
511 dentry = csr1212_find_keyval(dir, kv);
512
513 if (!dentry)
514 return;
515
516 if (dentry->prev)
517 dentry->prev->next = dentry->next;
518 if (dentry->next)
519 dentry->next->prev = dentry->prev;
520 if (dir->value.directory.dentries_head == dentry)
521 dir->value.directory.dentries_head = dentry->next;
522 if (dir->value.directory.dentries_tail == dentry)
523 dir->value.directory.dentries_tail = dentry->prev;
524
525 CSR1212_FREE(dentry);
526
527 csr1212_release_keyval(kv);
528}
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530/* This function is used to free the memory taken by a keyval. If the given
531 * keyval is a directory type, then any keyvals contained in that directory
532 * will be destroyed as well if their respective refcnts are 0. By means of
533 * list manipulation, this routine will descend a directory structure in a
534 * non-recursive manner. */
535void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
536{
537 struct csr1212_keyval *k, *a;
538 struct csr1212_dentry dentry;
539 struct csr1212_dentry *head, *tail;
540
541 dentry.kv = kv;
542 dentry.next = NULL;
543 dentry.prev = NULL;
544
545 head = &dentry;
546 tail = head;
547
548 while (head) {
549 k = head->kv;
550
551 while (k) {
552 k->refcnt--;
553
554 if (k->refcnt > 0)
555 break;
556
557 a = k->associate;
558
559 if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
560 /* If the current entry is a directory, then move all
561 * the entries to the destruction list. */
562 if (k->value.directory.dentries_head) {
563 tail->next = k->value.directory.dentries_head;
564 k->value.directory.dentries_head->prev = tail;
565 tail = k->value.directory.dentries_tail;
566 }
567 }
568 free_keyval(k);
569 k = a;
570 }
571
572 head = head->next;
573 if (head) {
574 if (head->prev && head->prev != &dentry) {
575 CSR1212_FREE(head->prev);
576 }
577 head->prev = NULL;
578 } else if (tail != &dentry)
579 CSR1212_FREE(tail);
580 }
581}
582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583void csr1212_destroy_csr(struct csr1212_csr *csr)
584{
585 struct csr1212_csr_rom_cache *c, *oc;
586 struct csr1212_cache_region *cr, *ocr;
587
588 csr1212_release_keyval(csr->root_kv);
589
590 c = csr->cache_head;
591 while (c) {
592 oc = c;
593 cr = c->filled_head;
594 while (cr) {
595 ocr = cr;
596 cr = cr->next;
597 CSR1212_FREE(ocr);
598 }
599 c = c->next;
600 CSR1212_FREE(oc);
601 }
602
603 CSR1212_FREE(csr);
604}
605
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607/* CSR Image Creation */
608
609static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
610{
611 struct csr1212_csr_rom_cache *cache;
Stefan Richter982610b2007-03-11 22:49:34 +0100612 u64 csr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Ben Collins1934b8b2005-07-09 20:01:23 -0400614 if (!csr || !csr->ops || !csr->ops->allocate_addr_range ||
615 !csr->ops->release_addr || csr->max_rom < 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100616 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 /* ROM size must be a multiple of csr->max_rom */
619 romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
620
621 csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private);
Ben Collins67372312006-06-12 18:15:31 -0400622 if (csr_addr == CSR1212_INVALID_ADDR_SPACE) {
Stefan Richter7fb9add2007-03-11 22:49:05 +0100623 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 }
625 if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
626 /* Invalid address returned from allocate_addr_range(). */
627 csr->ops->release_addr(csr_addr, csr->private);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100628 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
630
631 cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize);
632 if (!cache) {
633 csr->ops->release_addr(csr_addr, csr->private);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100634 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
636
637 cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM);
638 if (!cache->ext_rom) {
639 csr->ops->release_addr(csr_addr, csr->private);
640 CSR1212_FREE(cache);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100641 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 }
643
644 if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) {
645 csr1212_release_keyval(cache->ext_rom);
646 csr->ops->release_addr(csr_addr, csr->private);
647 CSR1212_FREE(cache);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100648 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
650 cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
651 cache->ext_rom->value.leaf.len = -1;
652 cache->ext_rom->value.leaf.data = cache->data;
653
654 /* Add cache to tail of cache list */
655 cache->prev = csr->cache_tail;
656 csr->cache_tail->next = cache;
657 csr->cache_tail = cache;
658 return CSR1212_SUCCESS;
659}
660
Stefan Richter6c88e472007-03-11 22:47:34 +0100661static void csr1212_remove_cache(struct csr1212_csr *csr,
662 struct csr1212_csr_rom_cache *cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
664 if (csr->cache_head == cache)
665 csr->cache_head = cache->next;
666 if (csr->cache_tail == cache)
667 csr->cache_tail = cache->prev;
668
669 if (cache->prev)
670 cache->prev->next = cache->next;
671 if (cache->next)
672 cache->next->prev = cache->prev;
673
674 if (cache->ext_rom) {
675 csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom);
676 csr1212_release_keyval(cache->ext_rom);
677 }
678
679 CSR1212_FREE(cache);
680}
681
682static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
683 struct csr1212_keyval **layout_tail)
684{
685 struct csr1212_dentry *dentry;
686 struct csr1212_keyval *dkv;
687 struct csr1212_keyval *last_extkey_spec = NULL;
688 struct csr1212_keyval *last_extkey = NULL;
689 int num_entries = 0;
690
691 for (dentry = dir->value.directory.dentries_head; dentry;
692 dentry = dentry->next) {
693 for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
694 /* Special Case: Extended Key Specifier_ID */
695 if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
696 if (last_extkey_spec == NULL) {
697 last_extkey_spec = dkv;
698 } else if (dkv->value.immediate != last_extkey_spec->value.immediate) {
699 last_extkey_spec = dkv;
700 } else {
701 continue;
702 }
703 /* Special Case: Extended Key */
704 } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
705 if (last_extkey == NULL) {
706 last_extkey = dkv;
707 } else if (dkv->value.immediate != last_extkey->value.immediate) {
708 last_extkey = dkv;
709 } else {
710 continue;
711 }
712 }
713
714 num_entries += 1;
715
716 switch(dkv->key.type) {
717 default:
718 case CSR1212_KV_TYPE_IMMEDIATE:
719 case CSR1212_KV_TYPE_CSR_OFFSET:
720 break;
721 case CSR1212_KV_TYPE_LEAF:
722 case CSR1212_KV_TYPE_DIRECTORY:
723 /* Remove from list */
724 if (dkv->prev && (dkv->prev->next == dkv))
725 dkv->prev->next = dkv->next;
726 if (dkv->next && (dkv->next->prev == dkv))
727 dkv->next->prev = dkv->prev;
728 //if (dkv == *layout_tail)
729 // *layout_tail = dkv->prev;
730
731 /* Special case: Extended ROM leafs */
732 if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
733 dkv->value.leaf.len = -1;
734 /* Don't add Extended ROM leafs in the layout list,
735 * they are handled differently. */
736 break;
737 }
738
739 /* Add to tail of list */
740 dkv->next = NULL;
741 dkv->prev = *layout_tail;
742 (*layout_tail)->next = dkv;
743 *layout_tail = dkv;
744 break;
745 }
746 }
747 }
748 return num_entries;
749}
750
Stefan Richter6c88e472007-03-11 22:47:34 +0100751static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
753 struct csr1212_keyval *ltail = kv;
754 size_t agg_size = 0;
755
756 while(kv) {
757 switch(kv->key.type) {
758 case CSR1212_KV_TYPE_LEAF:
759 /* Add 1 quadlet for crc/len field */
760 agg_size += kv->value.leaf.len + 1;
761 break;
762
763 case CSR1212_KV_TYPE_DIRECTORY:
764 kv->value.directory.len = csr1212_generate_layout_subdir(kv, &ltail);
765 /* Add 1 quadlet for crc/len field */
766 agg_size += kv->value.directory.len + 1;
767 break;
768 }
769 kv = kv->next;
770 }
771 return quads_to_bytes(agg_size);
772}
773
Stefan Richter6c88e472007-03-11 22:47:34 +0100774static struct csr1212_keyval *
775csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
776 struct csr1212_keyval *start_kv, int start_pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
778 struct csr1212_keyval *kv = start_kv;
779 struct csr1212_keyval *okv = start_kv;
780 int pos = start_pos;
781 int kv_len = 0, okv_len = 0;
782
783 cache->layout_head = kv;
784
785 while(kv && pos < cache->size) {
786 /* Special case: Extended ROM leafs */
787 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
788 kv->offset = cache->offset + pos;
789 }
790
791 switch(kv->key.type) {
792 case CSR1212_KV_TYPE_LEAF:
793 kv_len = kv->value.leaf.len;
794 break;
795
796 case CSR1212_KV_TYPE_DIRECTORY:
797 kv_len = kv->value.directory.len;
798 break;
799
800 default:
801 /* Should never get here */
802 break;
803 }
804
805 pos += quads_to_bytes(kv_len + 1);
806
807 if (pos <= cache->size) {
808 okv = kv;
809 okv_len = kv_len;
810 kv = kv->next;
811 }
812 }
813
814 cache->layout_tail = okv;
815 cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1);
816
817 return kv;
818}
819
Stefan Richter6c88e472007-03-11 22:47:34 +0100820#define CSR1212_KV_KEY_SHIFT 24
821#define CSR1212_KV_KEY_TYPE_SHIFT 6
822#define CSR1212_KV_KEY_ID_MASK 0x3f
823#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */
824
825static void
Stefan Richter982610b2007-03-11 22:49:34 +0100826csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 struct csr1212_dentry *dentry;
829 struct csr1212_keyval *last_extkey_spec = NULL;
830 struct csr1212_keyval *last_extkey = NULL;
831 int index = 0;
832
833 for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) {
834 struct csr1212_keyval *a;
835
836 for (a = dentry->kv; a; a = a->associate) {
Stefan Richter982610b2007-03-11 22:49:34 +0100837 u32 value = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
839 /* Special Case: Extended Key Specifier_ID */
840 if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
841 if (last_extkey_spec == NULL) {
842 last_extkey_spec = a;
843 } else if (a->value.immediate != last_extkey_spec->value.immediate) {
844 last_extkey_spec = a;
845 } else {
846 continue;
847 }
848 /* Special Case: Extended Key */
849 } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
850 if (last_extkey == NULL) {
851 last_extkey = a;
852 } else if (a->value.immediate != last_extkey->value.immediate) {
853 last_extkey = a;
854 } else {
855 continue;
856 }
857 }
858
859 switch(a->key.type) {
860 case CSR1212_KV_TYPE_IMMEDIATE:
861 value = a->value.immediate;
862 break;
863 case CSR1212_KV_TYPE_CSR_OFFSET:
864 value = a->value.csr_offset;
865 break;
866 case CSR1212_KV_TYPE_LEAF:
867 value = a->offset;
868 value -= dir->offset + quads_to_bytes(1+index);
869 value = bytes_to_quads(value);
870 break;
871 case CSR1212_KV_TYPE_DIRECTORY:
872 value = a->offset;
873 value -= dir->offset + quads_to_bytes(1+index);
874 value = bytes_to_quads(value);
875 break;
876 default:
877 /* Should never get here */
878 break; /* GDB breakpoint */
879 }
880
881 value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT;
882 value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
883 (CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100884 data_buffer[index] = cpu_to_be32(value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 index++;
886 }
887 }
888}
889
Stefan Richter6c88e472007-03-11 22:47:34 +0100890struct csr1212_keyval_img {
Stefan Richter982610b2007-03-11 22:49:34 +0100891 u16 length;
892 u16 crc;
Stefan Richter6c88e472007-03-11 22:47:34 +0100893
894 /* Must be last */
Stefan Richter982610b2007-03-11 22:49:34 +0100895 u32 data[0]; /* older gcc can't handle [] which is standard */
Stefan Richter6c88e472007-03-11 22:47:34 +0100896};
897
898static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
900 struct csr1212_keyval *kv, *nkv;
901 struct csr1212_keyval_img *kvi;
902
903 for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) {
904 kvi = (struct csr1212_keyval_img *)
905 (cache->data + bytes_to_quads(kv->offset - cache->offset));
906 switch(kv->key.type) {
907 default:
908 case CSR1212_KV_TYPE_IMMEDIATE:
909 case CSR1212_KV_TYPE_CSR_OFFSET:
910 /* Should never get here */
911 break; /* GDB breakpoint */
912
913 case CSR1212_KV_TYPE_LEAF:
914 /* Don't copy over Extended ROM areas, they are
915 * already filled out! */
916 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
917 memcpy(kvi->data, kv->value.leaf.data,
918 quads_to_bytes(kv->value.leaf.len));
919
Stefan Richter7fb9add2007-03-11 22:49:05 +0100920 kvi->length = cpu_to_be16(kv->value.leaf.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
922 break;
923
924 case CSR1212_KV_TYPE_DIRECTORY:
925 csr1212_generate_tree_subdir(kv, kvi->data);
926
Stefan Richter7fb9add2007-03-11 22:49:05 +0100927 kvi->length = cpu_to_be16(kv->value.directory.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len);
929 break;
930 }
931
932 nkv = kv->next;
933 if (kv->prev)
934 kv->prev->next = NULL;
935 if (kv->next)
936 kv->next->prev = NULL;
937 kv->prev = NULL;
938 kv->next = NULL;
939 }
940}
941
Stefan Richter982610b2007-03-11 22:49:34 +0100942#define CSR1212_EXTENDED_ROM_SIZE (0x10000 * sizeof(u32))
Stefan Richter6c88e472007-03-11 22:47:34 +0100943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944int csr1212_generate_csr_image(struct csr1212_csr *csr)
945{
946 struct csr1212_bus_info_block_img *bi;
947 struct csr1212_csr_rom_cache *cache;
948 struct csr1212_keyval *kv;
949 size_t agg_size;
950 int ret;
951 int init_offset;
952
953 if (!csr)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100954 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 cache = csr->cache_head;
957
958 bi = (struct csr1212_bus_info_block_img*)cache->data;
959
960 bi->length = bytes_to_quads(csr->bus_info_len) - 1;
961 bi->crc_length = bi->length;
962 bi->crc = csr1212_crc16(bi->data, bi->crc_length);
963
964 csr->root_kv->next = NULL;
965 csr->root_kv->prev = NULL;
966
967 agg_size = csr1212_generate_layout_order(csr->root_kv);
968
969 init_offset = csr->bus_info_len;
970
971 for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) {
972 if (!cache) {
973 /* Estimate approximate number of additional cache
974 * regions needed (it assumes that the cache holding
975 * the first 1K Config ROM space always exists). */
976 int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
Stefan Richter982610b2007-03-11 22:49:34 +0100977 (2 * sizeof(u32))) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979 /* Add additional cache regions, extras will be
980 * removed later */
981 for (; est_c; est_c--) {
982 ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE);
983 if (ret != CSR1212_SUCCESS)
984 return ret;
985 }
986 /* Need to re-layout for additional cache regions */
987 agg_size = csr1212_generate_layout_order(csr->root_kv);
988 kv = csr->root_kv;
989 cache = csr->cache_head;
990 init_offset = csr->bus_info_len;
991 }
992 kv = csr1212_generate_positions(cache, kv, init_offset);
993 agg_size -= cache->len;
Stefan Richter982610b2007-03-11 22:49:34 +0100994 init_offset = sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 }
996
997 /* Remove unused, excess cache regions */
998 while (cache) {
999 struct csr1212_csr_rom_cache *oc = cache;
1000
1001 cache = cache->next;
1002 csr1212_remove_cache(csr, oc);
1003 }
1004
1005 /* Go through the list backward so that when done, the correct CRC
1006 * will be calculated for the Extended ROM areas. */
1007 for(cache = csr->cache_tail; cache; cache = cache->prev) {
1008 /* Only Extended ROM caches should have this set. */
1009 if (cache->ext_rom) {
1010 int leaf_size;
1011
1012 /* Make sure the Extended ROM leaf is a multiple of
1013 * max_rom in size. */
Ben Collins1934b8b2005-07-09 20:01:23 -04001014 if (csr->max_rom < 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001015 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 leaf_size = (cache->len + (csr->max_rom - 1)) &
1017 ~(csr->max_rom - 1);
1018
1019 /* Zero out the unused ROM region */
1020 memset(cache->data + bytes_to_quads(cache->len), 0x00,
1021 leaf_size - cache->len);
1022
1023 /* Subtract leaf header */
Stefan Richter982610b2007-03-11 22:49:34 +01001024 leaf_size -= sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 /* Update the Extended ROM leaf length */
1027 cache->ext_rom->value.leaf.len =
1028 bytes_to_quads(leaf_size);
1029 } else {
1030 /* Zero out the unused ROM region */
1031 memset(cache->data + bytes_to_quads(cache->len), 0x00,
1032 cache->size - cache->len);
1033 }
1034
1035 /* Copy the data into the cache buffer */
1036 csr1212_fill_cache(cache);
1037
1038 if (cache != csr->cache_head) {
1039 /* Set the length and CRC of the extended ROM. */
1040 struct csr1212_keyval_img *kvi =
1041 (struct csr1212_keyval_img*)cache->data;
Stefan Richter982610b2007-03-11 22:49:34 +01001042 u16 len = bytes_to_quads(cache->len) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Stefan Richter7fb9add2007-03-11 22:49:05 +01001044 kvi->length = cpu_to_be16(len);
1045 kvi->crc = csr1212_crc16(kvi->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
1047 }
1048
1049 return CSR1212_SUCCESS;
1050}
1051
Stefan Richter982610b2007-03-11 22:49:34 +01001052int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053{
1054 struct csr1212_csr_rom_cache *cache;
1055
1056 for (cache = csr->cache_head; cache; cache = cache->next) {
1057 if (offset >= cache->offset &&
1058 (offset + len) <= (cache->offset + cache->size)) {
1059 memcpy(buffer,
1060 &cache->data[bytes_to_quads(offset - cache->offset)],
1061 len);
1062 return CSR1212_SUCCESS;
1063 }
1064 }
Stefan Richter7fb9add2007-03-11 22:49:05 +01001065 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066}
1067
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069/* Parse a chunk of data as a Config ROM */
1070
1071static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
1072{
1073 struct csr1212_bus_info_block_img *bi;
1074 struct csr1212_cache_region *cr;
1075 int i;
1076 int ret;
1077
1078 /* IEEE 1212 says that the entire bus info block should be readable in
1079 * a single transaction regardless of the max_rom value.
1080 * Unfortunately, many IEEE 1394 devices do not abide by that, so the
1081 * bus info block will be read 1 quadlet at a time. The rest of the
1082 * ConfigROM will be read according to the max_rom field. */
Stefan Richter982610b2007-03-11 22:49:34 +01001083 for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
Stefan Richter982610b2007-03-11 22:49:34 +01001085 sizeof(u32),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 &csr->cache_head->data[bytes_to_quads(i)],
1087 csr->private);
1088 if (ret != CSR1212_SUCCESS)
1089 return ret;
Stefan Richterb2051f82007-01-03 19:32:13 +01001090
1091 /* check ROM header's info_length */
1092 if (i == 0 &&
Stefan Richter7fb9add2007-03-11 22:49:05 +01001093 be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
Stefan Richterb2051f82007-01-03 19:32:13 +01001094 bytes_to_quads(csr->bus_info_len) - 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001095 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
1097
1098 bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
1099 csr->crc_len = quads_to_bytes(bi->crc_length);
1100
1101 /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not
1102 * always the case, so read the rest of the crc area 1 quadlet at a time. */
Stefan Richter982610b2007-03-11 22:49:34 +01001103 for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
Stefan Richter982610b2007-03-11 22:49:34 +01001105 sizeof(u32),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 &csr->cache_head->data[bytes_to_quads(i)],
1107 csr->private);
1108 if (ret != CSR1212_SUCCESS)
1109 return ret;
1110 }
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112#if 0
1113 /* Apparently there are too many differnt wrong implementations of the
1114 * CRC algorithm that verifying them is moot. */
1115 if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
1116 (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
Stefan Richter7fb9add2007-03-11 22:49:05 +01001117 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118#endif
1119
Stefan Richter85511582005-11-07 06:31:45 -05001120 cr = CSR1212_MALLOC(sizeof(*cr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (!cr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001122 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124 cr->next = NULL;
1125 cr->prev = NULL;
1126 cr->offset_start = 0;
1127 cr->offset_end = csr->crc_len + 4;
1128
1129 csr->cache_head->filled_head = cr;
1130 csr->cache_head->filled_tail = cr;
1131
1132 return CSR1212_SUCCESS;
1133}
1134
Stefan Richter7fb9add2007-03-11 22:49:05 +01001135#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
Stefan Richter6c88e472007-03-11 22:47:34 +01001136#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
1137#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
1138#define CSR1212_KV_VAL_MASK 0xffffff
Stefan Richter7fb9add2007-03-11 22:49:05 +01001139#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
Stefan Richter6c88e472007-03-11 22:47:34 +01001140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
Stefan Richter982610b2007-03-11 22:49:34 +01001142 u32 ki, u32 kv_pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 int ret = CSR1212_SUCCESS;
1145 struct csr1212_keyval *k = NULL;
Stefan Richter982610b2007-03-11 22:49:34 +01001146 u32 offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
1148 switch(CSR1212_KV_KEY_TYPE(ki)) {
1149 case CSR1212_KV_TYPE_IMMEDIATE:
1150 k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
1151 CSR1212_KV_VAL(ki));
1152 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001153 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 goto fail;
1155 }
1156
1157 k->refcnt = 0; /* Don't keep local reference when parsing. */
1158 break;
1159
1160 case CSR1212_KV_TYPE_CSR_OFFSET:
1161 k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
1162 CSR1212_KV_VAL(ki));
1163 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001164 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 goto fail;
1166 }
1167 k->refcnt = 0; /* Don't keep local reference when parsing. */
1168 break;
1169
1170 default:
1171 /* Compute the offset from 0xffff f000 0000. */
1172 offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
1173 if (offset == kv_pos) {
1174 /* Uh-oh. Can't have a relative offset of 0 for Leaves
1175 * or Directories. The Config ROM image is most likely
1176 * messed up, so we'll just abort here. */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001177 ret = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 goto fail;
1179 }
1180
1181 k = csr1212_find_keyval_offset(dir, offset);
1182
1183 if (k)
1184 break; /* Found it. */
1185
1186 if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) {
1187 k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
1188 } else {
1189 k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
1190 }
1191 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001192 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 goto fail;
1194 }
1195 k->refcnt = 0; /* Don't keep local reference when parsing. */
1196 k->valid = 0; /* Contents not read yet so it's not valid. */
1197 k->offset = offset;
1198
1199 k->prev = dir;
1200 k->next = dir->next;
1201 dir->next->prev = k;
1202 dir->next = k;
1203 }
1204 ret = csr1212_attach_keyval_to_directory(dir, k);
1205
1206fail:
Stefan Richter6c88e472007-03-11 22:47:34 +01001207 if (ret != CSR1212_SUCCESS && k != NULL)
1208 free_keyval(k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 return ret;
1210}
1211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212int csr1212_parse_keyval(struct csr1212_keyval *kv,
1213 struct csr1212_csr_rom_cache *cache)
1214{
1215 struct csr1212_keyval_img *kvi;
1216 int i;
1217 int ret = CSR1212_SUCCESS;
1218 int kvi_len;
1219
1220 kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset -
1221 cache->offset)];
Stefan Richter7fb9add2007-03-11 22:49:05 +01001222 kvi_len = be16_to_cpu(kvi->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224#if 0
1225 /* Apparently there are too many differnt wrong implementations of the
1226 * CRC algorithm that verifying them is moot. */
1227 if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
1228 (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001229 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 goto fail;
1231 }
1232#endif
1233
1234 switch(kv->key.type) {
1235 case CSR1212_KV_TYPE_DIRECTORY:
1236 for (i = 0; i < kvi_len; i++) {
Stefan Richter982610b2007-03-11 22:49:34 +01001237 u32 ki = kvi->data[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239 /* Some devices put null entries in their unit
1240 * directories. If we come across such an entry,
1241 * then skip it. */
1242 if (ki == 0x0)
1243 continue;
1244 ret = csr1212_parse_dir_entry(kv, ki,
1245 (kv->offset +
1246 quads_to_bytes(i + 1)));
1247 }
1248 kv->value.directory.len = kvi_len;
1249 break;
1250
1251 case CSR1212_KV_TYPE_LEAF:
1252 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
1253 kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len));
Stefan Richter85511582005-11-07 06:31:45 -05001254 if (!kv->value.leaf.data) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001255 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 goto fail;
1257 }
1258
1259 kv->value.leaf.len = kvi_len;
1260 memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len));
1261 }
1262 break;
1263 }
1264
1265 kv->valid = 1;
1266
1267fail:
1268 return ret;
1269}
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
1272{
1273 struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
1274 struct csr1212_keyval_img *kvi = NULL;
1275 struct csr1212_csr_rom_cache *cache;
1276 int cache_index;
Stefan Richter982610b2007-03-11 22:49:34 +01001277 u64 addr;
1278 u32 *cache_ptr;
1279 u16 kv_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
Ben Collins1934b8b2005-07-09 20:01:23 -04001281 if (!csr || !kv || csr->max_rom < 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001282 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
1284 /* First find which cache the data should be in (or go in if not read
1285 * yet). */
1286 for (cache = csr->cache_head; cache; cache = cache->next) {
1287 if (kv->offset >= cache->offset &&
1288 kv->offset < (cache->offset + cache->size))
1289 break;
1290 }
1291
1292 if (!cache) {
Stefan Richter982610b2007-03-11 22:49:34 +01001293 u32 q, cache_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
1295 /* Only create a new cache for Extended ROM leaves. */
1296 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001297 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 if (csr->ops->bus_read(csr,
1300 CSR1212_REGISTER_SPACE_BASE + kv->offset,
Stefan Richter982610b2007-03-11 22:49:34 +01001301 sizeof(u32), &q, csr->private)) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001302 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 }
1304
Stefan Richter7fb9add2007-03-11 22:49:05 +01001305 kv->value.leaf.len = be32_to_cpu(q) >> 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
1307 cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
1308 (csr->max_rom - 1)) & ~(csr->max_rom - 1);
1309
1310 cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
1311 if (!cache)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001312 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
1314 kv->value.leaf.data = &cache->data[1];
1315 csr->cache_tail->next = cache;
1316 cache->prev = csr->cache_tail;
1317 cache->next = NULL;
1318 csr->cache_tail = cache;
1319 cache->filled_head =
Stefan Richter85511582005-11-07 06:31:45 -05001320 CSR1212_MALLOC(sizeof(*cache->filled_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 if (!cache->filled_head) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001322 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 }
1324
1325 cache->filled_head->offset_start = 0;
Stefan Richter982610b2007-03-11 22:49:34 +01001326 cache->filled_head->offset_end = sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 cache->filled_tail = cache->filled_head;
1328 cache->filled_head->next = NULL;
1329 cache->filled_head->prev = NULL;
1330 cache->data[0] = q;
1331
1332 /* Don't read the entire extended ROM now. Pieces of it will
1333 * be read when entries inside it are read. */
1334 return csr1212_parse_keyval(kv, cache);
1335 }
1336
1337 cache_index = kv->offset - cache->offset;
1338
1339 /* Now seach read portions of the cache to see if it is there. */
1340 for (cr = cache->filled_head; cr; cr = cr->next) {
1341 if (cache_index < cr->offset_start) {
Stefan Richter85511582005-11-07 06:31:45 -05001342 newcr = CSR1212_MALLOC(sizeof(*newcr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 if (!newcr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001344 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 newcr->offset_start = cache_index & ~(csr->max_rom - 1);
1347 newcr->offset_end = newcr->offset_start;
1348 newcr->next = cr;
1349 newcr->prev = cr->prev;
1350 cr->prev = newcr;
1351 cr = newcr;
1352 break;
1353 } else if ((cache_index >= cr->offset_start) &&
1354 (cache_index < cr->offset_end)) {
1355 kvi = (struct csr1212_keyval_img*)
1356 (&cache->data[bytes_to_quads(cache_index)]);
Stefan Richter7fb9add2007-03-11 22:49:05 +01001357 kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 break;
1359 } else if (cache_index == cr->offset_end)
1360 break;
1361 }
1362
1363 if (!cr) {
1364 cr = cache->filled_tail;
Stefan Richter85511582005-11-07 06:31:45 -05001365 newcr = CSR1212_MALLOC(sizeof(*newcr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (!newcr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001367 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369 newcr->offset_start = cache_index & ~(csr->max_rom - 1);
1370 newcr->offset_end = newcr->offset_start;
1371 newcr->prev = cr;
1372 newcr->next = cr->next;
1373 cr->next = newcr;
1374 cr = newcr;
1375 cache->filled_tail = newcr;
1376 }
1377
1378 while(!kvi || cr->offset_end < cache_index + kv_len) {
1379 cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
1380 ~(csr->max_rom - 1))];
1381
1382 addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
1383 cr->offset_end) & ~(csr->max_rom - 1);
1384
1385 if (csr->ops->bus_read(csr, addr, csr->max_rom, cache_ptr,
1386 csr->private)) {
1387 if (csr->max_rom == 4)
1388 /* We've got problems! */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001389 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
1391 /* Apperently the max_rom value was a lie, set it to
1392 * do quadlet reads and try again. */
1393 csr->max_rom = 4;
1394 continue;
1395 }
1396
1397 cr->offset_end += csr->max_rom - (cr->offset_end &
1398 (csr->max_rom - 1));
1399
1400 if (!kvi && (cr->offset_end > cache_index)) {
1401 kvi = (struct csr1212_keyval_img*)
1402 (&cache->data[bytes_to_quads(cache_index)]);
Stefan Richter7fb9add2007-03-11 22:49:05 +01001403 kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
1405
1406 if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
1407 /* The Leaf or Directory claims its length extends
1408 * beyond the ConfigROM image region and thus beyond the
1409 * end of our cache region. Therefore, we abort now
1410 * rather than seg faulting later. */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001411 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413
1414 ncr = cr->next;
1415
1416 if (ncr && (cr->offset_end >= ncr->offset_start)) {
1417 /* consolidate region entries */
1418 ncr->offset_start = cr->offset_start;
1419
1420 if (cr->prev)
1421 cr->prev->next = cr->next;
1422 ncr->prev = cr->prev;
1423 if (cache->filled_head == cr)
1424 cache->filled_head = ncr;
1425 CSR1212_FREE(cr);
1426 cr = ncr;
1427 }
1428 }
1429
1430 return csr1212_parse_keyval(kv, cache);
1431}
1432
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433int csr1212_parse_csr(struct csr1212_csr *csr)
1434{
1435 static const int mr_map[] = { 4, 64, 1024, 0 };
1436 struct csr1212_dentry *dentry;
1437 int ret;
1438
Ben Collins1934b8b2005-07-09 20:01:23 -04001439 if (!csr || !csr->ops || !csr->ops->bus_read)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001440 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
1442 ret = csr1212_parse_bus_info_block(csr);
1443 if (ret != CSR1212_SUCCESS)
1444 return ret;
1445
1446 if (!csr->ops->get_max_rom)
1447 csr->max_rom = mr_map[0]; /* default value */
Ben Collins1934b8b2005-07-09 20:01:23 -04001448 else {
1449 int i = csr->ops->get_max_rom(csr->bus_info_data,
1450 csr->private);
1451 if (i & ~0x3)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001452 return -EINVAL;
Ben Collins1934b8b2005-07-09 20:01:23 -04001453 csr->max_rom = mr_map[i];
1454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455
1456 csr->cache_head->layout_head = csr->root_kv;
1457 csr->cache_head->layout_tail = csr->root_kv;
1458
1459 csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
1460 csr->bus_info_len;
1461
1462 csr->root_kv->valid = 0;
1463 csr->root_kv->next = csr->root_kv;
1464 csr->root_kv->prev = csr->root_kv;
Jody McIntyre5303a982005-11-22 12:17:11 -05001465 ret = _csr1212_read_keyval(csr, csr->root_kv);
1466 if (ret != CSR1212_SUCCESS)
1467 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
1469 /* Scan through the Root directory finding all extended ROM regions
1470 * and make cache regions for them */
1471 for (dentry = csr->root_kv->value.directory.dentries_head;
1472 dentry; dentry = dentry->next) {
Jody McIntyrea96074e2005-11-22 12:17:14 -05001473 if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
1474 !dentry->kv->valid) {
Jody McIntyre5303a982005-11-22 12:17:11 -05001475 ret = _csr1212_read_keyval(csr, dentry->kv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (ret != CSR1212_SUCCESS)
1477 return ret;
1478 }
1479 }
1480
1481 return CSR1212_SUCCESS;
1482}