blob: f5867236255b877ab37d9e7da062369c6cdce6a6 [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)
48static const u_int8_t 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
84#define quads_to_bytes(_q) ((_q) * sizeof(u_int32_t))
85#define bytes_to_quads(_b) (((_b) + sizeof(u_int32_t) - 1) / sizeof(u_int32_t))
86
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
96static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length)
97{
98 int shift;
99 u_int32_t data;
100 u_int16_t sum, crc = 0;
101
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. */
119static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length)
120{
121 int shift;
122 u_int32_t data;
123 u_int16_t sum, crc = 0;
124
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 *
153csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u_int32_t 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,
205 const u_int32_t *bus_info_data, int max_rom)
206{
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key)
215{
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
238struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value)
239{
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 *
251csr1212_new_leaf(u_int8_t 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 *
279csr1212_new_csr_offset(u_int8_t key, u_int32_t 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
293struct csr1212_keyval *csr1212_new_directory(u_int8_t key)
294{
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 *
390csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t specifier_id,
391 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 *
435csr1212_new_textual_descriptor_leaf(u_int8_t cwidth, u_int16_t cset,
436 u_int16_t language, const void *data,
437 size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
439 struct csr1212_keyval *kv;
440 char *lstr;
441
442 kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len +
443 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
444 if (!kv)
445 return NULL;
446
447 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth);
448 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset);
449 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
450
451 lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
452
453 /* make sure last quadlet is zeroed out */
454 *((u_int32_t*)&(lstr[(data_len - 1) & ~0x3])) = 0;
455
456 /* don't copy the NUL terminator */
457 memcpy(lstr, data, data_len);
458
459 return kv;
460}
461
462static int csr1212_check_minimal_ascii(const char *s)
463{
464 static const char minimal_ascii_table[] = {
465 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
466 0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00,
467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
469 0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27,
470 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
471 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
472 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
473 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
474 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
475 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
476 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
477 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
478 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
479 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
480 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
481 };
482 for (; *s; s++) {
483 if (minimal_ascii_table[*s & 0x7F] != *s)
484 return -1; /* failed */
485 }
486 /* String conforms to minimal-ascii, as specified by IEEE 1212,
487 * par. 7.4 */
488 return 0;
489}
490
491struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
492{
493 /* Check if string conform to minimal_ascii format */
494 if (csr1212_check_minimal_ascii(s))
495 return NULL;
496
497 /* IEEE 1212, par. 7.5.4.1 Textual descriptors (minimal ASCII) */
498 return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s));
499}
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502/* Destruction Routines */
503
504void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
505 struct csr1212_keyval *kv)
506{
507 struct csr1212_dentry *dentry;
508
509 if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
510 return;
511
512 dentry = csr1212_find_keyval(dir, kv);
513
514 if (!dentry)
515 return;
516
517 if (dentry->prev)
518 dentry->prev->next = dentry->next;
519 if (dentry->next)
520 dentry->next->prev = dentry->prev;
521 if (dir->value.directory.dentries_head == dentry)
522 dir->value.directory.dentries_head = dentry->next;
523 if (dir->value.directory.dentries_tail == dentry)
524 dir->value.directory.dentries_tail = dentry->prev;
525
526 CSR1212_FREE(dentry);
527
528 csr1212_release_keyval(kv);
529}
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531/* This function is used to free the memory taken by a keyval. If the given
532 * keyval is a directory type, then any keyvals contained in that directory
533 * will be destroyed as well if their respective refcnts are 0. By means of
534 * list manipulation, this routine will descend a directory structure in a
535 * non-recursive manner. */
536void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
537{
538 struct csr1212_keyval *k, *a;
539 struct csr1212_dentry dentry;
540 struct csr1212_dentry *head, *tail;
541
542 dentry.kv = kv;
543 dentry.next = NULL;
544 dentry.prev = NULL;
545
546 head = &dentry;
547 tail = head;
548
549 while (head) {
550 k = head->kv;
551
552 while (k) {
553 k->refcnt--;
554
555 if (k->refcnt > 0)
556 break;
557
558 a = k->associate;
559
560 if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
561 /* If the current entry is a directory, then move all
562 * the entries to the destruction list. */
563 if (k->value.directory.dentries_head) {
564 tail->next = k->value.directory.dentries_head;
565 k->value.directory.dentries_head->prev = tail;
566 tail = k->value.directory.dentries_tail;
567 }
568 }
569 free_keyval(k);
570 k = a;
571 }
572
573 head = head->next;
574 if (head) {
575 if (head->prev && head->prev != &dentry) {
576 CSR1212_FREE(head->prev);
577 }
578 head->prev = NULL;
579 } else if (tail != &dentry)
580 CSR1212_FREE(tail);
581 }
582}
583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584void csr1212_destroy_csr(struct csr1212_csr *csr)
585{
586 struct csr1212_csr_rom_cache *c, *oc;
587 struct csr1212_cache_region *cr, *ocr;
588
589 csr1212_release_keyval(csr->root_kv);
590
591 c = csr->cache_head;
592 while (c) {
593 oc = c;
594 cr = c->filled_head;
595 while (cr) {
596 ocr = cr;
597 cr = cr->next;
598 CSR1212_FREE(ocr);
599 }
600 c = c->next;
601 CSR1212_FREE(oc);
602 }
603
604 CSR1212_FREE(csr);
605}
606
607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608/* CSR Image Creation */
609
610static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
611{
612 struct csr1212_csr_rom_cache *cache;
613 u_int64_t csr_addr;
614
Ben Collins1934b8b2005-07-09 20:01:23 -0400615 if (!csr || !csr->ops || !csr->ops->allocate_addr_range ||
616 !csr->ops->release_addr || csr->max_rom < 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100617 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 /* ROM size must be a multiple of csr->max_rom */
620 romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
621
622 csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private);
Ben Collins67372312006-06-12 18:15:31 -0400623 if (csr_addr == CSR1212_INVALID_ADDR_SPACE) {
Stefan Richter7fb9add2007-03-11 22:49:05 +0100624 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
626 if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
627 /* Invalid address returned from allocate_addr_range(). */
628 csr->ops->release_addr(csr_addr, csr->private);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100629 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
631
632 cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize);
633 if (!cache) {
634 csr->ops->release_addr(csr_addr, csr->private);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100635 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
637
638 cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM);
639 if (!cache->ext_rom) {
640 csr->ops->release_addr(csr_addr, csr->private);
641 CSR1212_FREE(cache);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100642 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644
645 if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) {
646 csr1212_release_keyval(cache->ext_rom);
647 csr->ops->release_addr(csr_addr, csr->private);
648 CSR1212_FREE(cache);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100649 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
651 cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
652 cache->ext_rom->value.leaf.len = -1;
653 cache->ext_rom->value.leaf.data = cache->data;
654
655 /* Add cache to tail of cache list */
656 cache->prev = csr->cache_tail;
657 csr->cache_tail->next = cache;
658 csr->cache_tail = cache;
659 return CSR1212_SUCCESS;
660}
661
Stefan Richter6c88e472007-03-11 22:47:34 +0100662static void csr1212_remove_cache(struct csr1212_csr *csr,
663 struct csr1212_csr_rom_cache *cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 if (csr->cache_head == cache)
666 csr->cache_head = cache->next;
667 if (csr->cache_tail == cache)
668 csr->cache_tail = cache->prev;
669
670 if (cache->prev)
671 cache->prev->next = cache->next;
672 if (cache->next)
673 cache->next->prev = cache->prev;
674
675 if (cache->ext_rom) {
676 csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom);
677 csr1212_release_keyval(cache->ext_rom);
678 }
679
680 CSR1212_FREE(cache);
681}
682
683static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
684 struct csr1212_keyval **layout_tail)
685{
686 struct csr1212_dentry *dentry;
687 struct csr1212_keyval *dkv;
688 struct csr1212_keyval *last_extkey_spec = NULL;
689 struct csr1212_keyval *last_extkey = NULL;
690 int num_entries = 0;
691
692 for (dentry = dir->value.directory.dentries_head; dentry;
693 dentry = dentry->next) {
694 for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
695 /* Special Case: Extended Key Specifier_ID */
696 if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
697 if (last_extkey_spec == NULL) {
698 last_extkey_spec = dkv;
699 } else if (dkv->value.immediate != last_extkey_spec->value.immediate) {
700 last_extkey_spec = dkv;
701 } else {
702 continue;
703 }
704 /* Special Case: Extended Key */
705 } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
706 if (last_extkey == NULL) {
707 last_extkey = dkv;
708 } else if (dkv->value.immediate != last_extkey->value.immediate) {
709 last_extkey = dkv;
710 } else {
711 continue;
712 }
713 }
714
715 num_entries += 1;
716
717 switch(dkv->key.type) {
718 default:
719 case CSR1212_KV_TYPE_IMMEDIATE:
720 case CSR1212_KV_TYPE_CSR_OFFSET:
721 break;
722 case CSR1212_KV_TYPE_LEAF:
723 case CSR1212_KV_TYPE_DIRECTORY:
724 /* Remove from list */
725 if (dkv->prev && (dkv->prev->next == dkv))
726 dkv->prev->next = dkv->next;
727 if (dkv->next && (dkv->next->prev == dkv))
728 dkv->next->prev = dkv->prev;
729 //if (dkv == *layout_tail)
730 // *layout_tail = dkv->prev;
731
732 /* Special case: Extended ROM leafs */
733 if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
734 dkv->value.leaf.len = -1;
735 /* Don't add Extended ROM leafs in the layout list,
736 * they are handled differently. */
737 break;
738 }
739
740 /* Add to tail of list */
741 dkv->next = NULL;
742 dkv->prev = *layout_tail;
743 (*layout_tail)->next = dkv;
744 *layout_tail = dkv;
745 break;
746 }
747 }
748 }
749 return num_entries;
750}
751
Stefan Richter6c88e472007-03-11 22:47:34 +0100752static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
754 struct csr1212_keyval *ltail = kv;
755 size_t agg_size = 0;
756
757 while(kv) {
758 switch(kv->key.type) {
759 case CSR1212_KV_TYPE_LEAF:
760 /* Add 1 quadlet for crc/len field */
761 agg_size += kv->value.leaf.len + 1;
762 break;
763
764 case CSR1212_KV_TYPE_DIRECTORY:
765 kv->value.directory.len = csr1212_generate_layout_subdir(kv, &ltail);
766 /* Add 1 quadlet for crc/len field */
767 agg_size += kv->value.directory.len + 1;
768 break;
769 }
770 kv = kv->next;
771 }
772 return quads_to_bytes(agg_size);
773}
774
Stefan Richter6c88e472007-03-11 22:47:34 +0100775static struct csr1212_keyval *
776csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
777 struct csr1212_keyval *start_kv, int start_pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 struct csr1212_keyval *kv = start_kv;
780 struct csr1212_keyval *okv = start_kv;
781 int pos = start_pos;
782 int kv_len = 0, okv_len = 0;
783
784 cache->layout_head = kv;
785
786 while(kv && pos < cache->size) {
787 /* Special case: Extended ROM leafs */
788 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
789 kv->offset = cache->offset + pos;
790 }
791
792 switch(kv->key.type) {
793 case CSR1212_KV_TYPE_LEAF:
794 kv_len = kv->value.leaf.len;
795 break;
796
797 case CSR1212_KV_TYPE_DIRECTORY:
798 kv_len = kv->value.directory.len;
799 break;
800
801 default:
802 /* Should never get here */
803 break;
804 }
805
806 pos += quads_to_bytes(kv_len + 1);
807
808 if (pos <= cache->size) {
809 okv = kv;
810 okv_len = kv_len;
811 kv = kv->next;
812 }
813 }
814
815 cache->layout_tail = okv;
816 cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1);
817
818 return kv;
819}
820
Stefan Richter6c88e472007-03-11 22:47:34 +0100821#define CSR1212_KV_KEY_SHIFT 24
822#define CSR1212_KV_KEY_TYPE_SHIFT 6
823#define CSR1212_KV_KEY_ID_MASK 0x3f
824#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */
825
826static void
827csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u_int32_t *data_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
829 struct csr1212_dentry *dentry;
830 struct csr1212_keyval *last_extkey_spec = NULL;
831 struct csr1212_keyval *last_extkey = NULL;
832 int index = 0;
833
834 for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) {
835 struct csr1212_keyval *a;
836
837 for (a = dentry->kv; a; a = a->associate) {
838 u_int32_t value = 0;
839
840 /* Special Case: Extended Key Specifier_ID */
841 if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
842 if (last_extkey_spec == NULL) {
843 last_extkey_spec = a;
844 } else if (a->value.immediate != last_extkey_spec->value.immediate) {
845 last_extkey_spec = a;
846 } else {
847 continue;
848 }
849 /* Special Case: Extended Key */
850 } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
851 if (last_extkey == NULL) {
852 last_extkey = a;
853 } else if (a->value.immediate != last_extkey->value.immediate) {
854 last_extkey = a;
855 } else {
856 continue;
857 }
858 }
859
860 switch(a->key.type) {
861 case CSR1212_KV_TYPE_IMMEDIATE:
862 value = a->value.immediate;
863 break;
864 case CSR1212_KV_TYPE_CSR_OFFSET:
865 value = a->value.csr_offset;
866 break;
867 case CSR1212_KV_TYPE_LEAF:
868 value = a->offset;
869 value -= dir->offset + quads_to_bytes(1+index);
870 value = bytes_to_quads(value);
871 break;
872 case CSR1212_KV_TYPE_DIRECTORY:
873 value = a->offset;
874 value -= dir->offset + quads_to_bytes(1+index);
875 value = bytes_to_quads(value);
876 break;
877 default:
878 /* Should never get here */
879 break; /* GDB breakpoint */
880 }
881
882 value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT;
883 value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
884 (CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100885 data_buffer[index] = cpu_to_be32(value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 index++;
887 }
888 }
889}
890
Stefan Richter6c88e472007-03-11 22:47:34 +0100891struct csr1212_keyval_img {
892 u_int16_t length;
893 u_int16_t crc;
894
895 /* Must be last */
896 csr1212_quad_t data[0]; /* older gcc can't handle [] which is standard */
897};
898
899static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
901 struct csr1212_keyval *kv, *nkv;
902 struct csr1212_keyval_img *kvi;
903
904 for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) {
905 kvi = (struct csr1212_keyval_img *)
906 (cache->data + bytes_to_quads(kv->offset - cache->offset));
907 switch(kv->key.type) {
908 default:
909 case CSR1212_KV_TYPE_IMMEDIATE:
910 case CSR1212_KV_TYPE_CSR_OFFSET:
911 /* Should never get here */
912 break; /* GDB breakpoint */
913
914 case CSR1212_KV_TYPE_LEAF:
915 /* Don't copy over Extended ROM areas, they are
916 * already filled out! */
917 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
918 memcpy(kvi->data, kv->value.leaf.data,
919 quads_to_bytes(kv->value.leaf.len));
920
Stefan Richter7fb9add2007-03-11 22:49:05 +0100921 kvi->length = cpu_to_be16(kv->value.leaf.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
923 break;
924
925 case CSR1212_KV_TYPE_DIRECTORY:
926 csr1212_generate_tree_subdir(kv, kvi->data);
927
Stefan Richter7fb9add2007-03-11 22:49:05 +0100928 kvi->length = cpu_to_be16(kv->value.directory.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len);
930 break;
931 }
932
933 nkv = kv->next;
934 if (kv->prev)
935 kv->prev->next = NULL;
936 if (kv->next)
937 kv->next->prev = NULL;
938 kv->prev = NULL;
939 kv->next = NULL;
940 }
941}
942
Stefan Richter6c88e472007-03-11 22:47:34 +0100943#define CSR1212_EXTENDED_ROM_SIZE (0x10000 * sizeof(u_int32_t))
944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945int csr1212_generate_csr_image(struct csr1212_csr *csr)
946{
947 struct csr1212_bus_info_block_img *bi;
948 struct csr1212_csr_rom_cache *cache;
949 struct csr1212_keyval *kv;
950 size_t agg_size;
951 int ret;
952 int init_offset;
953
954 if (!csr)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100955 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 cache = csr->cache_head;
958
959 bi = (struct csr1212_bus_info_block_img*)cache->data;
960
961 bi->length = bytes_to_quads(csr->bus_info_len) - 1;
962 bi->crc_length = bi->length;
963 bi->crc = csr1212_crc16(bi->data, bi->crc_length);
964
965 csr->root_kv->next = NULL;
966 csr->root_kv->prev = NULL;
967
968 agg_size = csr1212_generate_layout_order(csr->root_kv);
969
970 init_offset = csr->bus_info_len;
971
972 for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) {
973 if (!cache) {
974 /* Estimate approximate number of additional cache
975 * regions needed (it assumes that the cache holding
976 * the first 1K Config ROM space always exists). */
977 int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
978 (2 * sizeof(u_int32_t))) + 1;
979
980 /* Add additional cache regions, extras will be
981 * removed later */
982 for (; est_c; est_c--) {
983 ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE);
984 if (ret != CSR1212_SUCCESS)
985 return ret;
986 }
987 /* Need to re-layout for additional cache regions */
988 agg_size = csr1212_generate_layout_order(csr->root_kv);
989 kv = csr->root_kv;
990 cache = csr->cache_head;
991 init_offset = csr->bus_info_len;
992 }
993 kv = csr1212_generate_positions(cache, kv, init_offset);
994 agg_size -= cache->len;
995 init_offset = sizeof(u_int32_t);
996 }
997
998 /* Remove unused, excess cache regions */
999 while (cache) {
1000 struct csr1212_csr_rom_cache *oc = cache;
1001
1002 cache = cache->next;
1003 csr1212_remove_cache(csr, oc);
1004 }
1005
1006 /* Go through the list backward so that when done, the correct CRC
1007 * will be calculated for the Extended ROM areas. */
1008 for(cache = csr->cache_tail; cache; cache = cache->prev) {
1009 /* Only Extended ROM caches should have this set. */
1010 if (cache->ext_rom) {
1011 int leaf_size;
1012
1013 /* Make sure the Extended ROM leaf is a multiple of
1014 * max_rom in size. */
Ben Collins1934b8b2005-07-09 20:01:23 -04001015 if (csr->max_rom < 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001016 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 leaf_size = (cache->len + (csr->max_rom - 1)) &
1018 ~(csr->max_rom - 1);
1019
1020 /* Zero out the unused ROM region */
1021 memset(cache->data + bytes_to_quads(cache->len), 0x00,
1022 leaf_size - cache->len);
1023
1024 /* Subtract leaf header */
1025 leaf_size -= sizeof(u_int32_t);
1026
1027 /* Update the Extended ROM leaf length */
1028 cache->ext_rom->value.leaf.len =
1029 bytes_to_quads(leaf_size);
1030 } else {
1031 /* Zero out the unused ROM region */
1032 memset(cache->data + bytes_to_quads(cache->len), 0x00,
1033 cache->size - cache->len);
1034 }
1035
1036 /* Copy the data into the cache buffer */
1037 csr1212_fill_cache(cache);
1038
1039 if (cache != csr->cache_head) {
1040 /* Set the length and CRC of the extended ROM. */
1041 struct csr1212_keyval_img *kvi =
1042 (struct csr1212_keyval_img*)cache->data;
Stefan Richter7fb9add2007-03-11 22:49:05 +01001043 u_int16_t len = bytes_to_quads(cache->len) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Stefan Richter7fb9add2007-03-11 22:49:05 +01001045 kvi->length = cpu_to_be16(len);
1046 kvi->crc = csr1212_crc16(kvi->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
1048 }
1049
1050 return CSR1212_SUCCESS;
1051}
1052
1053int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, u_int32_t len)
1054{
1055 struct csr1212_csr_rom_cache *cache;
1056
1057 for (cache = csr->cache_head; cache; cache = cache->next) {
1058 if (offset >= cache->offset &&
1059 (offset + len) <= (cache->offset + cache->size)) {
1060 memcpy(buffer,
1061 &cache->data[bytes_to_quads(offset - cache->offset)],
1062 len);
1063 return CSR1212_SUCCESS;
1064 }
1065 }
Stefan Richter7fb9add2007-03-11 22:49:05 +01001066 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067}
1068
1069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070/* Parse a chunk of data as a Config ROM */
1071
1072static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
1073{
1074 struct csr1212_bus_info_block_img *bi;
1075 struct csr1212_cache_region *cr;
1076 int i;
1077 int ret;
1078
1079 /* IEEE 1212 says that the entire bus info block should be readable in
1080 * a single transaction regardless of the max_rom value.
1081 * Unfortunately, many IEEE 1394 devices do not abide by that, so the
1082 * bus info block will be read 1 quadlet at a time. The rest of the
1083 * ConfigROM will be read according to the max_rom field. */
1084 for (i = 0; i < csr->bus_info_len; i += sizeof(csr1212_quad_t)) {
1085 ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
1086 sizeof(csr1212_quad_t),
1087 &csr->cache_head->data[bytes_to_quads(i)],
1088 csr->private);
1089 if (ret != CSR1212_SUCCESS)
1090 return ret;
Stefan Richterb2051f82007-01-03 19:32:13 +01001091
1092 /* check ROM header's info_length */
1093 if (i == 0 &&
Stefan Richter7fb9add2007-03-11 22:49:05 +01001094 be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
Stefan Richterb2051f82007-01-03 19:32:13 +01001095 bytes_to_quads(csr->bus_info_len) - 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001096 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 }
1098
1099 bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
1100 csr->crc_len = quads_to_bytes(bi->crc_length);
1101
1102 /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not
1103 * always the case, so read the rest of the crc area 1 quadlet at a time. */
1104 for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(csr1212_quad_t)) {
1105 ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
1106 sizeof(csr1212_quad_t),
1107 &csr->cache_head->data[bytes_to_quads(i)],
1108 csr->private);
1109 if (ret != CSR1212_SUCCESS)
1110 return ret;
1111 }
1112
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113#if 0
1114 /* Apparently there are too many differnt wrong implementations of the
1115 * CRC algorithm that verifying them is moot. */
1116 if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
1117 (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
Stefan Richter7fb9add2007-03-11 22:49:05 +01001118 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119#endif
1120
Stefan Richter85511582005-11-07 06:31:45 -05001121 cr = CSR1212_MALLOC(sizeof(*cr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 if (!cr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001123 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
1125 cr->next = NULL;
1126 cr->prev = NULL;
1127 cr->offset_start = 0;
1128 cr->offset_end = csr->crc_len + 4;
1129
1130 csr->cache_head->filled_head = cr;
1131 csr->cache_head->filled_tail = cr;
1132
1133 return CSR1212_SUCCESS;
1134}
1135
Stefan Richter7fb9add2007-03-11 22:49:05 +01001136#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
Stefan Richter6c88e472007-03-11 22:47:34 +01001137#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
1138#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
1139#define CSR1212_KV_VAL_MASK 0xffffff
Stefan Richter7fb9add2007-03-11 22:49:05 +01001140#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
Stefan Richter6c88e472007-03-11 22:47:34 +01001141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
1143 csr1212_quad_t ki,
1144 u_int32_t kv_pos)
1145{
1146 int ret = CSR1212_SUCCESS;
1147 struct csr1212_keyval *k = NULL;
1148 u_int32_t offset;
1149
1150 switch(CSR1212_KV_KEY_TYPE(ki)) {
1151 case CSR1212_KV_TYPE_IMMEDIATE:
1152 k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
1153 CSR1212_KV_VAL(ki));
1154 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001155 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 goto fail;
1157 }
1158
1159 k->refcnt = 0; /* Don't keep local reference when parsing. */
1160 break;
1161
1162 case CSR1212_KV_TYPE_CSR_OFFSET:
1163 k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
1164 CSR1212_KV_VAL(ki));
1165 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001166 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 goto fail;
1168 }
1169 k->refcnt = 0; /* Don't keep local reference when parsing. */
1170 break;
1171
1172 default:
1173 /* Compute the offset from 0xffff f000 0000. */
1174 offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
1175 if (offset == kv_pos) {
1176 /* Uh-oh. Can't have a relative offset of 0 for Leaves
1177 * or Directories. The Config ROM image is most likely
1178 * messed up, so we'll just abort here. */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001179 ret = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 goto fail;
1181 }
1182
1183 k = csr1212_find_keyval_offset(dir, offset);
1184
1185 if (k)
1186 break; /* Found it. */
1187
1188 if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) {
1189 k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
1190 } else {
1191 k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
1192 }
1193 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001194 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 goto fail;
1196 }
1197 k->refcnt = 0; /* Don't keep local reference when parsing. */
1198 k->valid = 0; /* Contents not read yet so it's not valid. */
1199 k->offset = offset;
1200
1201 k->prev = dir;
1202 k->next = dir->next;
1203 dir->next->prev = k;
1204 dir->next = k;
1205 }
1206 ret = csr1212_attach_keyval_to_directory(dir, k);
1207
1208fail:
Stefan Richter6c88e472007-03-11 22:47:34 +01001209 if (ret != CSR1212_SUCCESS && k != NULL)
1210 free_keyval(k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return ret;
1212}
1213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214int csr1212_parse_keyval(struct csr1212_keyval *kv,
1215 struct csr1212_csr_rom_cache *cache)
1216{
1217 struct csr1212_keyval_img *kvi;
1218 int i;
1219 int ret = CSR1212_SUCCESS;
1220 int kvi_len;
1221
1222 kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset -
1223 cache->offset)];
Stefan Richter7fb9add2007-03-11 22:49:05 +01001224 kvi_len = be16_to_cpu(kvi->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226#if 0
1227 /* Apparently there are too many differnt wrong implementations of the
1228 * CRC algorithm that verifying them is moot. */
1229 if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
1230 (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001231 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 goto fail;
1233 }
1234#endif
1235
1236 switch(kv->key.type) {
1237 case CSR1212_KV_TYPE_DIRECTORY:
1238 for (i = 0; i < kvi_len; i++) {
1239 csr1212_quad_t ki = kvi->data[i];
1240
1241 /* Some devices put null entries in their unit
1242 * directories. If we come across such an entry,
1243 * then skip it. */
1244 if (ki == 0x0)
1245 continue;
1246 ret = csr1212_parse_dir_entry(kv, ki,
1247 (kv->offset +
1248 quads_to_bytes(i + 1)));
1249 }
1250 kv->value.directory.len = kvi_len;
1251 break;
1252
1253 case CSR1212_KV_TYPE_LEAF:
1254 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
1255 kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len));
Stefan Richter85511582005-11-07 06:31:45 -05001256 if (!kv->value.leaf.data) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001257 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 goto fail;
1259 }
1260
1261 kv->value.leaf.len = kvi_len;
1262 memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len));
1263 }
1264 break;
1265 }
1266
1267 kv->valid = 1;
1268
1269fail:
1270 return ret;
1271}
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
1274{
1275 struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
1276 struct csr1212_keyval_img *kvi = NULL;
1277 struct csr1212_csr_rom_cache *cache;
1278 int cache_index;
1279 u_int64_t addr;
1280 u_int32_t *cache_ptr;
1281 u_int16_t kv_len = 0;
1282
Ben Collins1934b8b2005-07-09 20:01:23 -04001283 if (!csr || !kv || csr->max_rom < 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001284 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
1286 /* First find which cache the data should be in (or go in if not read
1287 * yet). */
1288 for (cache = csr->cache_head; cache; cache = cache->next) {
1289 if (kv->offset >= cache->offset &&
1290 kv->offset < (cache->offset + cache->size))
1291 break;
1292 }
1293
1294 if (!cache) {
1295 csr1212_quad_t q;
1296 u_int32_t cache_size;
1297
1298 /* Only create a new cache for Extended ROM leaves. */
1299 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001300 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 if (csr->ops->bus_read(csr,
1303 CSR1212_REGISTER_SPACE_BASE + kv->offset,
1304 sizeof(csr1212_quad_t), &q, csr->private)) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001305 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
1307
Stefan Richter7fb9add2007-03-11 22:49:05 +01001308 kv->value.leaf.len = be32_to_cpu(q) >> 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
1310 cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
1311 (csr->max_rom - 1)) & ~(csr->max_rom - 1);
1312
1313 cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
1314 if (!cache)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001315 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
1317 kv->value.leaf.data = &cache->data[1];
1318 csr->cache_tail->next = cache;
1319 cache->prev = csr->cache_tail;
1320 cache->next = NULL;
1321 csr->cache_tail = cache;
1322 cache->filled_head =
Stefan Richter85511582005-11-07 06:31:45 -05001323 CSR1212_MALLOC(sizeof(*cache->filled_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 if (!cache->filled_head) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001325 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 }
1327
1328 cache->filled_head->offset_start = 0;
1329 cache->filled_head->offset_end = sizeof(csr1212_quad_t);
1330 cache->filled_tail = cache->filled_head;
1331 cache->filled_head->next = NULL;
1332 cache->filled_head->prev = NULL;
1333 cache->data[0] = q;
1334
1335 /* Don't read the entire extended ROM now. Pieces of it will
1336 * be read when entries inside it are read. */
1337 return csr1212_parse_keyval(kv, cache);
1338 }
1339
1340 cache_index = kv->offset - cache->offset;
1341
1342 /* Now seach read portions of the cache to see if it is there. */
1343 for (cr = cache->filled_head; cr; cr = cr->next) {
1344 if (cache_index < cr->offset_start) {
Stefan Richter85511582005-11-07 06:31:45 -05001345 newcr = CSR1212_MALLOC(sizeof(*newcr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 if (!newcr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001347 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
1349 newcr->offset_start = cache_index & ~(csr->max_rom - 1);
1350 newcr->offset_end = newcr->offset_start;
1351 newcr->next = cr;
1352 newcr->prev = cr->prev;
1353 cr->prev = newcr;
1354 cr = newcr;
1355 break;
1356 } else if ((cache_index >= cr->offset_start) &&
1357 (cache_index < cr->offset_end)) {
1358 kvi = (struct csr1212_keyval_img*)
1359 (&cache->data[bytes_to_quads(cache_index)]);
Stefan Richter7fb9add2007-03-11 22:49:05 +01001360 kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 break;
1362 } else if (cache_index == cr->offset_end)
1363 break;
1364 }
1365
1366 if (!cr) {
1367 cr = cache->filled_tail;
Stefan Richter85511582005-11-07 06:31:45 -05001368 newcr = CSR1212_MALLOC(sizeof(*newcr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 if (!newcr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001370 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372 newcr->offset_start = cache_index & ~(csr->max_rom - 1);
1373 newcr->offset_end = newcr->offset_start;
1374 newcr->prev = cr;
1375 newcr->next = cr->next;
1376 cr->next = newcr;
1377 cr = newcr;
1378 cache->filled_tail = newcr;
1379 }
1380
1381 while(!kvi || cr->offset_end < cache_index + kv_len) {
1382 cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
1383 ~(csr->max_rom - 1))];
1384
1385 addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
1386 cr->offset_end) & ~(csr->max_rom - 1);
1387
1388 if (csr->ops->bus_read(csr, addr, csr->max_rom, cache_ptr,
1389 csr->private)) {
1390 if (csr->max_rom == 4)
1391 /* We've got problems! */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001392 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 /* Apperently the max_rom value was a lie, set it to
1395 * do quadlet reads and try again. */
1396 csr->max_rom = 4;
1397 continue;
1398 }
1399
1400 cr->offset_end += csr->max_rom - (cr->offset_end &
1401 (csr->max_rom - 1));
1402
1403 if (!kvi && (cr->offset_end > cache_index)) {
1404 kvi = (struct csr1212_keyval_img*)
1405 (&cache->data[bytes_to_quads(cache_index)]);
Stefan Richter7fb9add2007-03-11 22:49:05 +01001406 kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 }
1408
1409 if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
1410 /* The Leaf or Directory claims its length extends
1411 * beyond the ConfigROM image region and thus beyond the
1412 * end of our cache region. Therefore, we abort now
1413 * rather than seg faulting later. */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001414 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 }
1416
1417 ncr = cr->next;
1418
1419 if (ncr && (cr->offset_end >= ncr->offset_start)) {
1420 /* consolidate region entries */
1421 ncr->offset_start = cr->offset_start;
1422
1423 if (cr->prev)
1424 cr->prev->next = cr->next;
1425 ncr->prev = cr->prev;
1426 if (cache->filled_head == cr)
1427 cache->filled_head = ncr;
1428 CSR1212_FREE(cr);
1429 cr = ncr;
1430 }
1431 }
1432
1433 return csr1212_parse_keyval(kv, cache);
1434}
1435
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436int csr1212_parse_csr(struct csr1212_csr *csr)
1437{
1438 static const int mr_map[] = { 4, 64, 1024, 0 };
1439 struct csr1212_dentry *dentry;
1440 int ret;
1441
Ben Collins1934b8b2005-07-09 20:01:23 -04001442 if (!csr || !csr->ops || !csr->ops->bus_read)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001443 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
1445 ret = csr1212_parse_bus_info_block(csr);
1446 if (ret != CSR1212_SUCCESS)
1447 return ret;
1448
1449 if (!csr->ops->get_max_rom)
1450 csr->max_rom = mr_map[0]; /* default value */
Ben Collins1934b8b2005-07-09 20:01:23 -04001451 else {
1452 int i = csr->ops->get_max_rom(csr->bus_info_data,
1453 csr->private);
1454 if (i & ~0x3)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001455 return -EINVAL;
Ben Collins1934b8b2005-07-09 20:01:23 -04001456 csr->max_rom = mr_map[i];
1457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459 csr->cache_head->layout_head = csr->root_kv;
1460 csr->cache_head->layout_tail = csr->root_kv;
1461
1462 csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
1463 csr->bus_info_len;
1464
1465 csr->root_kv->valid = 0;
1466 csr->root_kv->next = csr->root_kv;
1467 csr->root_kv->prev = csr->root_kv;
Jody McIntyre5303a982005-11-22 12:17:11 -05001468 ret = _csr1212_read_keyval(csr, csr->root_kv);
1469 if (ret != CSR1212_SUCCESS)
1470 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
1472 /* Scan through the Root directory finding all extended ROM regions
1473 * and make cache regions for them */
1474 for (dentry = csr->root_kv->value.directory.dentries_head;
1475 dentry; dentry = dentry->next) {
Jody McIntyrea96074e2005-11-22 12:17:14 -05001476 if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
1477 !dentry->kv->valid) {
Jody McIntyre5303a982005-11-22 12:17:11 -05001478 ret = _csr1212_read_keyval(csr, dentry->kv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 if (ret != CSR1212_SUCCESS)
1480 return ret;
1481 }
1482 }
1483
1484 return CSR1212_SUCCESS;
1485}