blob: 54408cbe8f8f25c52c04d0f334eb750ec0719bfe [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>
Stefan Richter64ff7122007-03-11 22:50:13 +010038#include <asm/bug.h>
Stefan Richter7fb9add2007-03-11 22:49:05 +010039#include <asm/byteorder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41#include "csr1212.h"
42
43
44/* Permitted key type for each key id */
45#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
46#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
47#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
48#define __L (1 << CSR1212_KV_TYPE_LEAF)
Stefan Richter982610b2007-03-11 22:49:34 +010049static const u8 csr1212_key_id_type_map[0x30] = {
Andrea Guzzo0749aaa2006-12-08 00:53:24 +010050 __C, /* used by Apple iSight */
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 __D | __L, /* Descriptor */
52 __I | __D | __L, /* Bus_Dependent_Info */
53 __I | __D | __L, /* Vendor */
54 __I, /* Hardware_Version */
55 0, 0, /* Reserved */
Andrea Guzzo0749aaa2006-12-08 00:53:24 +010056 __D | __L | __I, /* Module */
57 __I, 0, 0, 0, /* used by Apple iSight, Reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 __I, /* Node_Capabilities */
59 __L, /* EUI_64 */
60 0, 0, 0, /* Reserved */
61 __D, /* Unit */
62 __I, /* Specifier_ID */
63 __I, /* Version */
64 __I | __C | __D | __L, /* Dependent_Info */
65 __L, /* Unit_Location */
66 0, /* Reserved */
67 __I, /* Model */
68 __D, /* Instance */
69 __L, /* Keyword */
70 __D, /* Feature */
71 __L, /* Extended_ROM */
72 __I, /* Extended_Key_Specifier_ID */
73 __I, /* Extended_Key */
74 __I | __C | __D | __L, /* Extended_Data */
75 __L, /* Modifiable_Descriptor */
76 __I, /* Directory_ID */
77 __I, /* Revision */
78};
79#undef __I
80#undef __C
81#undef __D
82#undef __L
83
84
Stefan Richter982610b2007-03-11 22:49:34 +010085#define quads_to_bytes(_q) ((_q) * sizeof(u32))
86#define bytes_to_quads(_b) (((_b) + sizeof(u32) - 1) / sizeof(u32))
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Stefan Richter6c88e472007-03-11 22:47:34 +010088static void free_keyval(struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
90 if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
91 (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
92 CSR1212_FREE(kv->value.leaf.data);
93
94 CSR1212_FREE(kv);
95}
96
Stefan Richter982610b2007-03-11 22:49:34 +010097static u16 csr1212_crc16(const u32 *buffer, size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
99 int shift;
Stefan Richter982610b2007-03-11 22:49:34 +0100100 u32 data;
101 u16 sum, crc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103 for (; length; length--) {
Stefan Richter7fb9add2007-03-11 22:49:05 +0100104 data = be32_to_cpu(*buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 buffer++;
106 for (shift = 28; shift >= 0; shift -= 4 ) {
107 sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
108 crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
109 }
110 crc &= 0xffff;
111 }
112
Stefan Richter7fb9add2007-03-11 22:49:05 +0100113 return cpu_to_be16(crc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114}
115
116#if 0
117/* Microsoft computes the CRC with the bytes in reverse order. Therefore we
118 * have a special version of the CRC algorithm to account for their buggy
119 * software. */
Stefan Richter982610b2007-03-11 22:49:34 +0100120static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
122 int shift;
Stefan Richter982610b2007-03-11 22:49:34 +0100123 u32 data;
124 u16 sum, crc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 for (; length; length--) {
Stefan Richter7fb9add2007-03-11 22:49:05 +0100127 data = le32_to_cpu(*buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 buffer++;
129 for (shift = 28; shift >= 0; shift -= 4 ) {
130 sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
131 crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
132 }
133 crc &= 0xffff;
134 }
135
Stefan Richter7fb9add2007-03-11 22:49:05 +0100136 return cpu_to_be16(crc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138#endif
139
Stefan Richter6c88e472007-03-11 22:47:34 +0100140static struct csr1212_dentry *
141csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
143 struct csr1212_dentry *pos;
144
145 for (pos = dir->value.directory.dentries_head;
146 pos != NULL; pos = pos->next) {
147 if (pos->kv == kv)
148 return pos;
149 }
150 return NULL;
151}
152
Stefan Richter6c88e472007-03-11 22:47:34 +0100153static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100154csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155{
156 struct csr1212_keyval *kv;
157
158 for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) {
159 if (kv->offset == offset)
160 return kv;
161 }
162 return NULL;
163}
164
165
166/* Creation Routines */
Stefan Richter6c88e472007-03-11 22:47:34 +0100167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
169 size_t bus_info_size, void *private)
170{
171 struct csr1212_csr *csr;
172
173 csr = CSR1212_MALLOC(sizeof(*csr));
174 if (!csr)
175 return NULL;
176
177 csr->cache_head =
178 csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
179 CSR1212_CONFIG_ROM_SPACE_SIZE);
180 if (!csr->cache_head) {
181 CSR1212_FREE(csr);
182 return NULL;
183 }
184
185 /* The keyval key id is not used for the root node, but a valid key id
186 * that can be used for a directory needs to be passed to
187 * csr1212_new_directory(). */
188 csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
189 if (!csr->root_kv) {
190 CSR1212_FREE(csr->cache_head);
191 CSR1212_FREE(csr);
192 return NULL;
193 }
194
195 csr->bus_info_data = csr->cache_head->data;
196 csr->bus_info_len = bus_info_size;
197 csr->crc_len = bus_info_size;
198 csr->ops = ops;
199 csr->private = private;
200 csr->cache_tail = csr->cache_head;
201
202 return csr;
203}
204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205void csr1212_init_local_csr(struct csr1212_csr *csr,
Stefan Richter982610b2007-03-11 22:49:34 +0100206 const u32 *bus_info_data, int max_rom)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 static const int mr_map[] = { 4, 64, 1024, 0 };
209
Ben Collins1934b8b2005-07-09 20:01:23 -0400210 BUG_ON(max_rom & ~0x3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 csr->max_rom = mr_map[max_rom];
212 memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
213}
214
Stefan Richter982610b2007-03-11 22:49:34 +0100215static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 struct csr1212_keyval *kv;
218
219 if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
220 return NULL;
221
222 kv = CSR1212_MALLOC(sizeof(*kv));
223 if (!kv)
224 return NULL;
225
226 kv->key.type = type;
227 kv->key.id = key;
228
229 kv->associate = NULL;
230 kv->refcnt = 1;
231
232 kv->next = NULL;
233 kv->prev = NULL;
234 kv->offset = 0;
235 kv->valid = 0;
236 return kv;
237}
238
Stefan Richter982610b2007-03-11 22:49:34 +0100239struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
241 struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
242
243 if (!kv)
244 return NULL;
245
246 kv->value.immediate = value;
247 kv->valid = 1;
248 return kv;
249}
250
Stefan Richter6c88e472007-03-11 22:47:34 +0100251static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100252csr1212_new_leaf(u8 key, const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
254 struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
255
256 if (!kv)
257 return NULL;
258
259 if (data_len > 0) {
260 kv->value.leaf.data = CSR1212_MALLOC(data_len);
261 if (!kv->value.leaf.data) {
262 CSR1212_FREE(kv);
263 return NULL;
264 }
265
266 if (data)
267 memcpy(kv->value.leaf.data, data, data_len);
268 } else {
269 kv->value.leaf.data = NULL;
270 }
271
272 kv->value.leaf.len = bytes_to_quads(data_len);
273 kv->offset = 0;
274 kv->valid = 1;
275
276 return kv;
277}
278
Stefan Richter6c88e472007-03-11 22:47:34 +0100279static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100280csr1212_new_csr_offset(u8 key, u32 csr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
282 struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
283
284 if (!kv)
285 return NULL;
286
287 kv->value.csr_offset = csr_offset;
288
289 kv->offset = 0;
290 kv->valid = 1;
291 return kv;
292}
293
Stefan Richter982610b2007-03-11 22:49:34 +0100294struct csr1212_keyval *csr1212_new_directory(u8 key)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295{
296 struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
297
298 if (!kv)
299 return NULL;
300
301 kv->value.directory.len = 0;
302 kv->offset = 0;
303 kv->value.directory.dentries_head = NULL;
304 kv->value.directory.dentries_tail = NULL;
305 kv->valid = 1;
306 return kv;
307}
308
Stefan Richter64ff7122007-03-11 22:50:13 +0100309void csr1212_associate_keyval(struct csr1212_keyval *kv,
310 struct csr1212_keyval *associate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Stefan Richter64ff7122007-03-11 22:50:13 +0100312 BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
313 (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
314 associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
315 associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
316 associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
317 associate->key.id < 0x30) ||
318 (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
319 associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
320 (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
321 associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
322 (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
323 kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
324 (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
325 kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 if (kv->associate)
328 csr1212_release_keyval(kv->associate);
329
330 associate->refcnt++;
331 kv->associate = associate;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
334int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
335 struct csr1212_keyval *kv)
336{
337 struct csr1212_dentry *dentry;
338
Stefan Richter64ff7122007-03-11 22:50:13 +0100339 BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 dentry = CSR1212_MALLOC(sizeof(*dentry));
342 if (!dentry)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100343 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 dentry->kv = kv;
346
347 kv->refcnt++;
348
349 dentry->next = NULL;
350 dentry->prev = dir->value.directory.dentries_tail;
351
352 if (!dir->value.directory.dentries_head)
353 dir->value.directory.dentries_head = dentry;
354
355 if (dir->value.directory.dentries_tail)
356 dir->value.directory.dentries_tail->next = dentry;
357 dir->value.directory.dentries_tail = dentry;
358
359 return CSR1212_SUCCESS;
360}
361
Stefan Richter6c88e472007-03-11 22:47:34 +0100362#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
363 (&((kv)->value.leaf.data[1]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Stefan Richter6c88e472007-03-11 22:47:34 +0100365#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
366 ((kv)->value.leaf.data[0] = \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100367 cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
368 ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
Stefan Richter6c88e472007-03-11 22:47:34 +0100369#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
370 ((kv)->value.leaf.data[0] = \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100371 cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
372 CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
373 ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
Stefan Richter6c88e472007-03-11 22:47:34 +0100375static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100376csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
Stefan Richter6c88e472007-03-11 22:47:34 +0100377 const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
379 struct csr1212_keyval *kv;
380
381 kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
382 data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
383 if (!kv)
384 return NULL;
385
386 CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
387 CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
388
389 if (data) {
390 memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
391 }
392
393 return kv;
394}
395
Stefan Richter6c88e472007-03-11 22:47:34 +0100396#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \
397 ((kv)->value.leaf.data[1] = \
398 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100399 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \
400 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \
401 cpu_to_be32(((width) & CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \
402 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Stefan Richter6c88e472007-03-11 22:47:34 +0100404#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \
405 ((kv)->value.leaf.data[1] = \
406 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100407 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \
408 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \
409 cpu_to_be32(((char_set) & \
410 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \
411 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))
Stefan Richter6c88e472007-03-11 22:47:34 +0100412
413#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
414 ((kv)->value.leaf.data[1] = \
415 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100416 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
417 cpu_to_be32(((language) & \
418 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
Stefan Richter6c88e472007-03-11 22:47:34 +0100419
420static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100421csr1212_new_textual_descriptor_leaf(u8 cwidth, u16 cset, u16 language,
422 const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
424 struct csr1212_keyval *kv;
425 char *lstr;
426
427 kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len +
428 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
429 if (!kv)
430 return NULL;
431
432 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth);
433 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset);
434 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
435
436 lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
437
438 /* make sure last quadlet is zeroed out */
Stefan Richter982610b2007-03-11 22:49:34 +0100439 *((u32*)&(lstr[(data_len - 1) & ~0x3])) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441 /* don't copy the NUL terminator */
442 memcpy(lstr, data, data_len);
443
444 return kv;
445}
446
447static int csr1212_check_minimal_ascii(const char *s)
448{
449 static const char minimal_ascii_table[] = {
450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
451 0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00,
452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
454 0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27,
455 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
456 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
457 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
458 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
459 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
460 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
461 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
462 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
463 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
464 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
465 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
466 };
467 for (; *s; s++) {
468 if (minimal_ascii_table[*s & 0x7F] != *s)
469 return -1; /* failed */
470 }
471 /* String conforms to minimal-ascii, as specified by IEEE 1212,
472 * par. 7.4 */
473 return 0;
474}
475
476struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
477{
478 /* Check if string conform to minimal_ascii format */
479 if (csr1212_check_minimal_ascii(s))
480 return NULL;
481
482 /* IEEE 1212, par. 7.5.4.1 Textual descriptors (minimal ASCII) */
483 return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s));
484}
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487/* Destruction Routines */
488
489void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
490 struct csr1212_keyval *kv)
491{
492 struct csr1212_dentry *dentry;
493
494 if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
495 return;
496
497 dentry = csr1212_find_keyval(dir, kv);
498
499 if (!dentry)
500 return;
501
502 if (dentry->prev)
503 dentry->prev->next = dentry->next;
504 if (dentry->next)
505 dentry->next->prev = dentry->prev;
506 if (dir->value.directory.dentries_head == dentry)
507 dir->value.directory.dentries_head = dentry->next;
508 if (dir->value.directory.dentries_tail == dentry)
509 dir->value.directory.dentries_tail = dentry->prev;
510
511 CSR1212_FREE(dentry);
512
513 csr1212_release_keyval(kv);
514}
515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516/* This function is used to free the memory taken by a keyval. If the given
517 * keyval is a directory type, then any keyvals contained in that directory
518 * will be destroyed as well if their respective refcnts are 0. By means of
519 * list manipulation, this routine will descend a directory structure in a
520 * non-recursive manner. */
521void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
522{
523 struct csr1212_keyval *k, *a;
524 struct csr1212_dentry dentry;
525 struct csr1212_dentry *head, *tail;
526
527 dentry.kv = kv;
528 dentry.next = NULL;
529 dentry.prev = NULL;
530
531 head = &dentry;
532 tail = head;
533
534 while (head) {
535 k = head->kv;
536
537 while (k) {
538 k->refcnt--;
539
540 if (k->refcnt > 0)
541 break;
542
543 a = k->associate;
544
545 if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
546 /* If the current entry is a directory, then move all
547 * the entries to the destruction list. */
548 if (k->value.directory.dentries_head) {
549 tail->next = k->value.directory.dentries_head;
550 k->value.directory.dentries_head->prev = tail;
551 tail = k->value.directory.dentries_tail;
552 }
553 }
554 free_keyval(k);
555 k = a;
556 }
557
558 head = head->next;
559 if (head) {
560 if (head->prev && head->prev != &dentry) {
561 CSR1212_FREE(head->prev);
562 }
563 head->prev = NULL;
564 } else if (tail != &dentry)
565 CSR1212_FREE(tail);
566 }
567}
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569void csr1212_destroy_csr(struct csr1212_csr *csr)
570{
571 struct csr1212_csr_rom_cache *c, *oc;
572 struct csr1212_cache_region *cr, *ocr;
573
574 csr1212_release_keyval(csr->root_kv);
575
576 c = csr->cache_head;
577 while (c) {
578 oc = c;
579 cr = c->filled_head;
580 while (cr) {
581 ocr = cr;
582 cr = cr->next;
583 CSR1212_FREE(ocr);
584 }
585 c = c->next;
586 CSR1212_FREE(oc);
587 }
588
589 CSR1212_FREE(csr);
590}
591
592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593/* CSR Image Creation */
594
595static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
596{
597 struct csr1212_csr_rom_cache *cache;
Stefan Richter982610b2007-03-11 22:49:34 +0100598 u64 csr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Stefan Richter64ff7122007-03-11 22:50:13 +0100600 BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
601 !csr->ops->release_addr || csr->max_rom < 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 /* ROM size must be a multiple of csr->max_rom */
604 romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
605
606 csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private);
Ben Collins67372312006-06-12 18:15:31 -0400607 if (csr_addr == CSR1212_INVALID_ADDR_SPACE) {
Stefan Richter7fb9add2007-03-11 22:49:05 +0100608 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610 if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
611 /* Invalid address returned from allocate_addr_range(). */
612 csr->ops->release_addr(csr_addr, csr->private);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100613 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
615
616 cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize);
617 if (!cache) {
618 csr->ops->release_addr(csr_addr, csr->private);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100619 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 }
621
622 cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM);
623 if (!cache->ext_rom) {
624 csr->ops->release_addr(csr_addr, csr->private);
625 CSR1212_FREE(cache);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100626 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
628
629 if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) {
630 csr1212_release_keyval(cache->ext_rom);
631 csr->ops->release_addr(csr_addr, csr->private);
632 CSR1212_FREE(cache);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100633 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
635 cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
636 cache->ext_rom->value.leaf.len = -1;
637 cache->ext_rom->value.leaf.data = cache->data;
638
639 /* Add cache to tail of cache list */
640 cache->prev = csr->cache_tail;
641 csr->cache_tail->next = cache;
642 csr->cache_tail = cache;
643 return CSR1212_SUCCESS;
644}
645
Stefan Richter6c88e472007-03-11 22:47:34 +0100646static void csr1212_remove_cache(struct csr1212_csr *csr,
647 struct csr1212_csr_rom_cache *cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
649 if (csr->cache_head == cache)
650 csr->cache_head = cache->next;
651 if (csr->cache_tail == cache)
652 csr->cache_tail = cache->prev;
653
654 if (cache->prev)
655 cache->prev->next = cache->next;
656 if (cache->next)
657 cache->next->prev = cache->prev;
658
659 if (cache->ext_rom) {
660 csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom);
661 csr1212_release_keyval(cache->ext_rom);
662 }
663
664 CSR1212_FREE(cache);
665}
666
667static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
668 struct csr1212_keyval **layout_tail)
669{
670 struct csr1212_dentry *dentry;
671 struct csr1212_keyval *dkv;
672 struct csr1212_keyval *last_extkey_spec = NULL;
673 struct csr1212_keyval *last_extkey = NULL;
674 int num_entries = 0;
675
676 for (dentry = dir->value.directory.dentries_head; dentry;
677 dentry = dentry->next) {
678 for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
679 /* Special Case: Extended Key Specifier_ID */
680 if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
681 if (last_extkey_spec == NULL) {
682 last_extkey_spec = dkv;
683 } else if (dkv->value.immediate != last_extkey_spec->value.immediate) {
684 last_extkey_spec = dkv;
685 } else {
686 continue;
687 }
688 /* Special Case: Extended Key */
689 } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
690 if (last_extkey == NULL) {
691 last_extkey = dkv;
692 } else if (dkv->value.immediate != last_extkey->value.immediate) {
693 last_extkey = dkv;
694 } else {
695 continue;
696 }
697 }
698
699 num_entries += 1;
700
701 switch(dkv->key.type) {
702 default:
703 case CSR1212_KV_TYPE_IMMEDIATE:
704 case CSR1212_KV_TYPE_CSR_OFFSET:
705 break;
706 case CSR1212_KV_TYPE_LEAF:
707 case CSR1212_KV_TYPE_DIRECTORY:
708 /* Remove from list */
709 if (dkv->prev && (dkv->prev->next == dkv))
710 dkv->prev->next = dkv->next;
711 if (dkv->next && (dkv->next->prev == dkv))
712 dkv->next->prev = dkv->prev;
713 //if (dkv == *layout_tail)
714 // *layout_tail = dkv->prev;
715
716 /* Special case: Extended ROM leafs */
717 if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
718 dkv->value.leaf.len = -1;
719 /* Don't add Extended ROM leafs in the layout list,
720 * they are handled differently. */
721 break;
722 }
723
724 /* Add to tail of list */
725 dkv->next = NULL;
726 dkv->prev = *layout_tail;
727 (*layout_tail)->next = dkv;
728 *layout_tail = dkv;
729 break;
730 }
731 }
732 }
733 return num_entries;
734}
735
Stefan Richter6c88e472007-03-11 22:47:34 +0100736static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
738 struct csr1212_keyval *ltail = kv;
739 size_t agg_size = 0;
740
741 while(kv) {
742 switch(kv->key.type) {
743 case CSR1212_KV_TYPE_LEAF:
744 /* Add 1 quadlet for crc/len field */
745 agg_size += kv->value.leaf.len + 1;
746 break;
747
748 case CSR1212_KV_TYPE_DIRECTORY:
749 kv->value.directory.len = csr1212_generate_layout_subdir(kv, &ltail);
750 /* Add 1 quadlet for crc/len field */
751 agg_size += kv->value.directory.len + 1;
752 break;
753 }
754 kv = kv->next;
755 }
756 return quads_to_bytes(agg_size);
757}
758
Stefan Richter6c88e472007-03-11 22:47:34 +0100759static struct csr1212_keyval *
760csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
761 struct csr1212_keyval *start_kv, int start_pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 struct csr1212_keyval *kv = start_kv;
764 struct csr1212_keyval *okv = start_kv;
765 int pos = start_pos;
766 int kv_len = 0, okv_len = 0;
767
768 cache->layout_head = kv;
769
770 while(kv && pos < cache->size) {
771 /* Special case: Extended ROM leafs */
772 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
773 kv->offset = cache->offset + pos;
774 }
775
776 switch(kv->key.type) {
777 case CSR1212_KV_TYPE_LEAF:
778 kv_len = kv->value.leaf.len;
779 break;
780
781 case CSR1212_KV_TYPE_DIRECTORY:
782 kv_len = kv->value.directory.len;
783 break;
784
785 default:
786 /* Should never get here */
787 break;
788 }
789
790 pos += quads_to_bytes(kv_len + 1);
791
792 if (pos <= cache->size) {
793 okv = kv;
794 okv_len = kv_len;
795 kv = kv->next;
796 }
797 }
798
799 cache->layout_tail = okv;
800 cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1);
801
802 return kv;
803}
804
Stefan Richter6c88e472007-03-11 22:47:34 +0100805#define CSR1212_KV_KEY_SHIFT 24
806#define CSR1212_KV_KEY_TYPE_SHIFT 6
807#define CSR1212_KV_KEY_ID_MASK 0x3f
808#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */
809
810static void
Stefan Richter982610b2007-03-11 22:49:34 +0100811csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
813 struct csr1212_dentry *dentry;
814 struct csr1212_keyval *last_extkey_spec = NULL;
815 struct csr1212_keyval *last_extkey = NULL;
816 int index = 0;
817
818 for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) {
819 struct csr1212_keyval *a;
820
821 for (a = dentry->kv; a; a = a->associate) {
Stefan Richter982610b2007-03-11 22:49:34 +0100822 u32 value = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 /* Special Case: Extended Key Specifier_ID */
825 if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
826 if (last_extkey_spec == NULL) {
827 last_extkey_spec = a;
828 } else if (a->value.immediate != last_extkey_spec->value.immediate) {
829 last_extkey_spec = a;
830 } else {
831 continue;
832 }
833 /* Special Case: Extended Key */
834 } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
835 if (last_extkey == NULL) {
836 last_extkey = a;
837 } else if (a->value.immediate != last_extkey->value.immediate) {
838 last_extkey = a;
839 } else {
840 continue;
841 }
842 }
843
844 switch(a->key.type) {
845 case CSR1212_KV_TYPE_IMMEDIATE:
846 value = a->value.immediate;
847 break;
848 case CSR1212_KV_TYPE_CSR_OFFSET:
849 value = a->value.csr_offset;
850 break;
851 case CSR1212_KV_TYPE_LEAF:
852 value = a->offset;
853 value -= dir->offset + quads_to_bytes(1+index);
854 value = bytes_to_quads(value);
855 break;
856 case CSR1212_KV_TYPE_DIRECTORY:
857 value = a->offset;
858 value -= dir->offset + quads_to_bytes(1+index);
859 value = bytes_to_quads(value);
860 break;
861 default:
862 /* Should never get here */
863 break; /* GDB breakpoint */
864 }
865
866 value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT;
867 value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
868 (CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100869 data_buffer[index] = cpu_to_be32(value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 index++;
871 }
872 }
873}
874
Stefan Richter6c88e472007-03-11 22:47:34 +0100875struct csr1212_keyval_img {
Stefan Richter982610b2007-03-11 22:49:34 +0100876 u16 length;
877 u16 crc;
Stefan Richter6c88e472007-03-11 22:47:34 +0100878
879 /* Must be last */
Stefan Richter982610b2007-03-11 22:49:34 +0100880 u32 data[0]; /* older gcc can't handle [] which is standard */
Stefan Richter6c88e472007-03-11 22:47:34 +0100881};
882
883static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 struct csr1212_keyval *kv, *nkv;
886 struct csr1212_keyval_img *kvi;
887
888 for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) {
889 kvi = (struct csr1212_keyval_img *)
890 (cache->data + bytes_to_quads(kv->offset - cache->offset));
891 switch(kv->key.type) {
892 default:
893 case CSR1212_KV_TYPE_IMMEDIATE:
894 case CSR1212_KV_TYPE_CSR_OFFSET:
895 /* Should never get here */
896 break; /* GDB breakpoint */
897
898 case CSR1212_KV_TYPE_LEAF:
899 /* Don't copy over Extended ROM areas, they are
900 * already filled out! */
901 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
902 memcpy(kvi->data, kv->value.leaf.data,
903 quads_to_bytes(kv->value.leaf.len));
904
Stefan Richter7fb9add2007-03-11 22:49:05 +0100905 kvi->length = cpu_to_be16(kv->value.leaf.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
907 break;
908
909 case CSR1212_KV_TYPE_DIRECTORY:
910 csr1212_generate_tree_subdir(kv, kvi->data);
911
Stefan Richter7fb9add2007-03-11 22:49:05 +0100912 kvi->length = cpu_to_be16(kv->value.directory.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len);
914 break;
915 }
916
917 nkv = kv->next;
918 if (kv->prev)
919 kv->prev->next = NULL;
920 if (kv->next)
921 kv->next->prev = NULL;
922 kv->prev = NULL;
923 kv->next = NULL;
924 }
925}
926
Stefan Richter982610b2007-03-11 22:49:34 +0100927#define CSR1212_EXTENDED_ROM_SIZE (0x10000 * sizeof(u32))
Stefan Richter6c88e472007-03-11 22:47:34 +0100928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929int csr1212_generate_csr_image(struct csr1212_csr *csr)
930{
931 struct csr1212_bus_info_block_img *bi;
932 struct csr1212_csr_rom_cache *cache;
933 struct csr1212_keyval *kv;
934 size_t agg_size;
935 int ret;
936 int init_offset;
937
Stefan Richter64ff7122007-03-11 22:50:13 +0100938 BUG_ON(!csr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 cache = csr->cache_head;
941
942 bi = (struct csr1212_bus_info_block_img*)cache->data;
943
944 bi->length = bytes_to_quads(csr->bus_info_len) - 1;
945 bi->crc_length = bi->length;
946 bi->crc = csr1212_crc16(bi->data, bi->crc_length);
947
948 csr->root_kv->next = NULL;
949 csr->root_kv->prev = NULL;
950
951 agg_size = csr1212_generate_layout_order(csr->root_kv);
952
953 init_offset = csr->bus_info_len;
954
955 for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) {
956 if (!cache) {
957 /* Estimate approximate number of additional cache
958 * regions needed (it assumes that the cache holding
959 * the first 1K Config ROM space always exists). */
960 int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
Stefan Richter982610b2007-03-11 22:49:34 +0100961 (2 * sizeof(u32))) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 /* Add additional cache regions, extras will be
964 * removed later */
965 for (; est_c; est_c--) {
966 ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE);
967 if (ret != CSR1212_SUCCESS)
968 return ret;
969 }
970 /* Need to re-layout for additional cache regions */
971 agg_size = csr1212_generate_layout_order(csr->root_kv);
972 kv = csr->root_kv;
973 cache = csr->cache_head;
974 init_offset = csr->bus_info_len;
975 }
976 kv = csr1212_generate_positions(cache, kv, init_offset);
977 agg_size -= cache->len;
Stefan Richter982610b2007-03-11 22:49:34 +0100978 init_offset = sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 }
980
981 /* Remove unused, excess cache regions */
982 while (cache) {
983 struct csr1212_csr_rom_cache *oc = cache;
984
985 cache = cache->next;
986 csr1212_remove_cache(csr, oc);
987 }
988
989 /* Go through the list backward so that when done, the correct CRC
990 * will be calculated for the Extended ROM areas. */
991 for(cache = csr->cache_tail; cache; cache = cache->prev) {
992 /* Only Extended ROM caches should have this set. */
993 if (cache->ext_rom) {
994 int leaf_size;
995
996 /* Make sure the Extended ROM leaf is a multiple of
997 * max_rom in size. */
Stefan Richter64ff7122007-03-11 22:50:13 +0100998 BUG_ON(csr->max_rom < 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 leaf_size = (cache->len + (csr->max_rom - 1)) &
1000 ~(csr->max_rom - 1);
1001
1002 /* Zero out the unused ROM region */
1003 memset(cache->data + bytes_to_quads(cache->len), 0x00,
1004 leaf_size - cache->len);
1005
1006 /* Subtract leaf header */
Stefan Richter982610b2007-03-11 22:49:34 +01001007 leaf_size -= sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
1009 /* Update the Extended ROM leaf length */
1010 cache->ext_rom->value.leaf.len =
1011 bytes_to_quads(leaf_size);
1012 } else {
1013 /* Zero out the unused ROM region */
1014 memset(cache->data + bytes_to_quads(cache->len), 0x00,
1015 cache->size - cache->len);
1016 }
1017
1018 /* Copy the data into the cache buffer */
1019 csr1212_fill_cache(cache);
1020
1021 if (cache != csr->cache_head) {
1022 /* Set the length and CRC of the extended ROM. */
1023 struct csr1212_keyval_img *kvi =
1024 (struct csr1212_keyval_img*)cache->data;
Stefan Richter982610b2007-03-11 22:49:34 +01001025 u16 len = bytes_to_quads(cache->len) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Stefan Richter7fb9add2007-03-11 22:49:05 +01001027 kvi->length = cpu_to_be16(len);
1028 kvi->crc = csr1212_crc16(kvi->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 }
1030 }
1031
1032 return CSR1212_SUCCESS;
1033}
1034
Stefan Richter982610b2007-03-11 22:49:34 +01001035int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036{
1037 struct csr1212_csr_rom_cache *cache;
1038
1039 for (cache = csr->cache_head; cache; cache = cache->next) {
1040 if (offset >= cache->offset &&
1041 (offset + len) <= (cache->offset + cache->size)) {
1042 memcpy(buffer,
1043 &cache->data[bytes_to_quads(offset - cache->offset)],
1044 len);
1045 return CSR1212_SUCCESS;
1046 }
1047 }
Stefan Richter7fb9add2007-03-11 22:49:05 +01001048 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049}
1050
1051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052/* Parse a chunk of data as a Config ROM */
1053
1054static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
1055{
1056 struct csr1212_bus_info_block_img *bi;
1057 struct csr1212_cache_region *cr;
1058 int i;
1059 int ret;
1060
1061 /* IEEE 1212 says that the entire bus info block should be readable in
1062 * a single transaction regardless of the max_rom value.
1063 * Unfortunately, many IEEE 1394 devices do not abide by that, so the
1064 * bus info block will be read 1 quadlet at a time. The rest of the
1065 * ConfigROM will be read according to the max_rom field. */
Stefan Richter982610b2007-03-11 22:49:34 +01001066 for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
Stefan Richter982610b2007-03-11 22:49:34 +01001068 sizeof(u32),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 &csr->cache_head->data[bytes_to_quads(i)],
1070 csr->private);
1071 if (ret != CSR1212_SUCCESS)
1072 return ret;
Stefan Richterb2051f82007-01-03 19:32:13 +01001073
1074 /* check ROM header's info_length */
1075 if (i == 0 &&
Stefan Richter7fb9add2007-03-11 22:49:05 +01001076 be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
Stefan Richterb2051f82007-01-03 19:32:13 +01001077 bytes_to_quads(csr->bus_info_len) - 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001078 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
1080
1081 bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
1082 csr->crc_len = quads_to_bytes(bi->crc_length);
1083
1084 /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not
1085 * always the case, so read the rest of the crc area 1 quadlet at a time. */
Stefan Richter982610b2007-03-11 22:49:34 +01001086 for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
Stefan Richter982610b2007-03-11 22:49:34 +01001088 sizeof(u32),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 &csr->cache_head->data[bytes_to_quads(i)],
1090 csr->private);
1091 if (ret != CSR1212_SUCCESS)
1092 return ret;
1093 }
1094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095#if 0
1096 /* Apparently there are too many differnt wrong implementations of the
1097 * CRC algorithm that verifying them is moot. */
1098 if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
1099 (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
Stefan Richter7fb9add2007-03-11 22:49:05 +01001100 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101#endif
1102
Stefan Richter85511582005-11-07 06:31:45 -05001103 cr = CSR1212_MALLOC(sizeof(*cr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 if (!cr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001105 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
1107 cr->next = NULL;
1108 cr->prev = NULL;
1109 cr->offset_start = 0;
1110 cr->offset_end = csr->crc_len + 4;
1111
1112 csr->cache_head->filled_head = cr;
1113 csr->cache_head->filled_tail = cr;
1114
1115 return CSR1212_SUCCESS;
1116}
1117
Stefan Richter7fb9add2007-03-11 22:49:05 +01001118#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
Stefan Richter6c88e472007-03-11 22:47:34 +01001119#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
1120#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
1121#define CSR1212_KV_VAL_MASK 0xffffff
Stefan Richter7fb9add2007-03-11 22:49:05 +01001122#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
Stefan Richter6c88e472007-03-11 22:47:34 +01001123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
Stefan Richter982610b2007-03-11 22:49:34 +01001125 u32 ki, u32 kv_pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126{
1127 int ret = CSR1212_SUCCESS;
1128 struct csr1212_keyval *k = NULL;
Stefan Richter982610b2007-03-11 22:49:34 +01001129 u32 offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131 switch(CSR1212_KV_KEY_TYPE(ki)) {
1132 case CSR1212_KV_TYPE_IMMEDIATE:
1133 k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
1134 CSR1212_KV_VAL(ki));
1135 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001136 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 goto fail;
1138 }
1139
1140 k->refcnt = 0; /* Don't keep local reference when parsing. */
1141 break;
1142
1143 case CSR1212_KV_TYPE_CSR_OFFSET:
1144 k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
1145 CSR1212_KV_VAL(ki));
1146 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001147 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 goto fail;
1149 }
1150 k->refcnt = 0; /* Don't keep local reference when parsing. */
1151 break;
1152
1153 default:
1154 /* Compute the offset from 0xffff f000 0000. */
1155 offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
1156 if (offset == kv_pos) {
1157 /* Uh-oh. Can't have a relative offset of 0 for Leaves
1158 * or Directories. The Config ROM image is most likely
1159 * messed up, so we'll just abort here. */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001160 ret = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 goto fail;
1162 }
1163
1164 k = csr1212_find_keyval_offset(dir, offset);
1165
1166 if (k)
1167 break; /* Found it. */
1168
1169 if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) {
1170 k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
1171 } else {
1172 k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
1173 }
1174 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001175 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 goto fail;
1177 }
1178 k->refcnt = 0; /* Don't keep local reference when parsing. */
1179 k->valid = 0; /* Contents not read yet so it's not valid. */
1180 k->offset = offset;
1181
1182 k->prev = dir;
1183 k->next = dir->next;
1184 dir->next->prev = k;
1185 dir->next = k;
1186 }
1187 ret = csr1212_attach_keyval_to_directory(dir, k);
1188
1189fail:
Stefan Richter6c88e472007-03-11 22:47:34 +01001190 if (ret != CSR1212_SUCCESS && k != NULL)
1191 free_keyval(k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return ret;
1193}
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195int csr1212_parse_keyval(struct csr1212_keyval *kv,
1196 struct csr1212_csr_rom_cache *cache)
1197{
1198 struct csr1212_keyval_img *kvi;
1199 int i;
1200 int ret = CSR1212_SUCCESS;
1201 int kvi_len;
1202
1203 kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset -
1204 cache->offset)];
Stefan Richter7fb9add2007-03-11 22:49:05 +01001205 kvi_len = be16_to_cpu(kvi->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
1207#if 0
1208 /* Apparently there are too many differnt wrong implementations of the
1209 * CRC algorithm that verifying them is moot. */
1210 if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
1211 (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001212 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 goto fail;
1214 }
1215#endif
1216
1217 switch(kv->key.type) {
1218 case CSR1212_KV_TYPE_DIRECTORY:
1219 for (i = 0; i < kvi_len; i++) {
Stefan Richter982610b2007-03-11 22:49:34 +01001220 u32 ki = kvi->data[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
1222 /* Some devices put null entries in their unit
1223 * directories. If we come across such an entry,
1224 * then skip it. */
1225 if (ki == 0x0)
1226 continue;
1227 ret = csr1212_parse_dir_entry(kv, ki,
1228 (kv->offset +
1229 quads_to_bytes(i + 1)));
1230 }
1231 kv->value.directory.len = kvi_len;
1232 break;
1233
1234 case CSR1212_KV_TYPE_LEAF:
1235 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
1236 kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len));
Stefan Richter85511582005-11-07 06:31:45 -05001237 if (!kv->value.leaf.data) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001238 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 goto fail;
1240 }
1241
1242 kv->value.leaf.len = kvi_len;
1243 memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len));
1244 }
1245 break;
1246 }
1247
1248 kv->valid = 1;
1249
1250fail:
1251 return ret;
1252}
1253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
1255{
1256 struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
1257 struct csr1212_keyval_img *kvi = NULL;
1258 struct csr1212_csr_rom_cache *cache;
1259 int cache_index;
Stefan Richter982610b2007-03-11 22:49:34 +01001260 u64 addr;
1261 u32 *cache_ptr;
1262 u16 kv_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Stefan Richter64ff7122007-03-11 22:50:13 +01001264 BUG_ON(!csr || !kv || csr->max_rom < 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
1266 /* First find which cache the data should be in (or go in if not read
1267 * yet). */
1268 for (cache = csr->cache_head; cache; cache = cache->next) {
1269 if (kv->offset >= cache->offset &&
1270 kv->offset < (cache->offset + cache->size))
1271 break;
1272 }
1273
1274 if (!cache) {
Stefan Richter982610b2007-03-11 22:49:34 +01001275 u32 q, cache_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
1277 /* Only create a new cache for Extended ROM leaves. */
1278 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001279 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281 if (csr->ops->bus_read(csr,
1282 CSR1212_REGISTER_SPACE_BASE + kv->offset,
Stefan Richter982610b2007-03-11 22:49:34 +01001283 sizeof(u32), &q, csr->private)) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001284 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 }
1286
Stefan Richter7fb9add2007-03-11 22:49:05 +01001287 kv->value.leaf.len = be32_to_cpu(q) >> 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
1289 cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
1290 (csr->max_rom - 1)) & ~(csr->max_rom - 1);
1291
1292 cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
1293 if (!cache)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001294 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
1296 kv->value.leaf.data = &cache->data[1];
1297 csr->cache_tail->next = cache;
1298 cache->prev = csr->cache_tail;
1299 cache->next = NULL;
1300 csr->cache_tail = cache;
1301 cache->filled_head =
Stefan Richter85511582005-11-07 06:31:45 -05001302 CSR1212_MALLOC(sizeof(*cache->filled_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if (!cache->filled_head) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001304 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 }
1306
1307 cache->filled_head->offset_start = 0;
Stefan Richter982610b2007-03-11 22:49:34 +01001308 cache->filled_head->offset_end = sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 cache->filled_tail = cache->filled_head;
1310 cache->filled_head->next = NULL;
1311 cache->filled_head->prev = NULL;
1312 cache->data[0] = q;
1313
1314 /* Don't read the entire extended ROM now. Pieces of it will
1315 * be read when entries inside it are read. */
1316 return csr1212_parse_keyval(kv, cache);
1317 }
1318
1319 cache_index = kv->offset - cache->offset;
1320
1321 /* Now seach read portions of the cache to see if it is there. */
1322 for (cr = cache->filled_head; cr; cr = cr->next) {
1323 if (cache_index < cr->offset_start) {
Stefan Richter85511582005-11-07 06:31:45 -05001324 newcr = CSR1212_MALLOC(sizeof(*newcr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 if (!newcr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001326 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
1328 newcr->offset_start = cache_index & ~(csr->max_rom - 1);
1329 newcr->offset_end = newcr->offset_start;
1330 newcr->next = cr;
1331 newcr->prev = cr->prev;
1332 cr->prev = newcr;
1333 cr = newcr;
1334 break;
1335 } else if ((cache_index >= cr->offset_start) &&
1336 (cache_index < cr->offset_end)) {
1337 kvi = (struct csr1212_keyval_img*)
1338 (&cache->data[bytes_to_quads(cache_index)]);
Stefan Richter7fb9add2007-03-11 22:49:05 +01001339 kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 break;
1341 } else if (cache_index == cr->offset_end)
1342 break;
1343 }
1344
1345 if (!cr) {
1346 cr = cache->filled_tail;
Stefan Richter85511582005-11-07 06:31:45 -05001347 newcr = CSR1212_MALLOC(sizeof(*newcr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 if (!newcr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001349 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
1351 newcr->offset_start = cache_index & ~(csr->max_rom - 1);
1352 newcr->offset_end = newcr->offset_start;
1353 newcr->prev = cr;
1354 newcr->next = cr->next;
1355 cr->next = newcr;
1356 cr = newcr;
1357 cache->filled_tail = newcr;
1358 }
1359
1360 while(!kvi || cr->offset_end < cache_index + kv_len) {
1361 cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
1362 ~(csr->max_rom - 1))];
1363
1364 addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
1365 cr->offset_end) & ~(csr->max_rom - 1);
1366
1367 if (csr->ops->bus_read(csr, addr, csr->max_rom, cache_ptr,
1368 csr->private)) {
1369 if (csr->max_rom == 4)
1370 /* We've got problems! */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001371 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
1373 /* Apperently the max_rom value was a lie, set it to
1374 * do quadlet reads and try again. */
1375 csr->max_rom = 4;
1376 continue;
1377 }
1378
1379 cr->offset_end += csr->max_rom - (cr->offset_end &
1380 (csr->max_rom - 1));
1381
1382 if (!kvi && (cr->offset_end > cache_index)) {
1383 kvi = (struct csr1212_keyval_img*)
1384 (&cache->data[bytes_to_quads(cache_index)]);
Stefan Richter7fb9add2007-03-11 22:49:05 +01001385 kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 }
1387
1388 if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
1389 /* The Leaf or Directory claims its length extends
1390 * beyond the ConfigROM image region and thus beyond the
1391 * end of our cache region. Therefore, we abort now
1392 * rather than seg faulting later. */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001393 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 }
1395
1396 ncr = cr->next;
1397
1398 if (ncr && (cr->offset_end >= ncr->offset_start)) {
1399 /* consolidate region entries */
1400 ncr->offset_start = cr->offset_start;
1401
1402 if (cr->prev)
1403 cr->prev->next = cr->next;
1404 ncr->prev = cr->prev;
1405 if (cache->filled_head == cr)
1406 cache->filled_head = ncr;
1407 CSR1212_FREE(cr);
1408 cr = ncr;
1409 }
1410 }
1411
1412 return csr1212_parse_keyval(kv, cache);
1413}
1414
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415int csr1212_parse_csr(struct csr1212_csr *csr)
1416{
1417 static const int mr_map[] = { 4, 64, 1024, 0 };
1418 struct csr1212_dentry *dentry;
1419 int ret;
1420
Stefan Richter64ff7122007-03-11 22:50:13 +01001421 BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
1423 ret = csr1212_parse_bus_info_block(csr);
1424 if (ret != CSR1212_SUCCESS)
1425 return ret;
1426
1427 if (!csr->ops->get_max_rom)
1428 csr->max_rom = mr_map[0]; /* default value */
Ben Collins1934b8b2005-07-09 20:01:23 -04001429 else {
1430 int i = csr->ops->get_max_rom(csr->bus_info_data,
1431 csr->private);
1432 if (i & ~0x3)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001433 return -EINVAL;
Ben Collins1934b8b2005-07-09 20:01:23 -04001434 csr->max_rom = mr_map[i];
1435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
1437 csr->cache_head->layout_head = csr->root_kv;
1438 csr->cache_head->layout_tail = csr->root_kv;
1439
1440 csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
1441 csr->bus_info_len;
1442
1443 csr->root_kv->valid = 0;
1444 csr->root_kv->next = csr->root_kv;
1445 csr->root_kv->prev = csr->root_kv;
Jody McIntyre5303a982005-11-22 12:17:11 -05001446 ret = _csr1212_read_keyval(csr, csr->root_kv);
1447 if (ret != CSR1212_SUCCESS)
1448 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
1450 /* Scan through the Root directory finding all extended ROM regions
1451 * and make cache regions for them */
1452 for (dentry = csr->root_kv->value.directory.dentries_head;
1453 dentry; dentry = dentry->next) {
Jody McIntyrea96074e2005-11-22 12:17:14 -05001454 if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
1455 !dentry->kv->valid) {
Jody McIntyre5303a982005-11-22 12:17:11 -05001456 ret = _csr1212_read_keyval(csr, dentry->kv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 if (ret != CSR1212_SUCCESS)
1458 return ret;
1459 }
1460 }
1461
1462 return CSR1212_SUCCESS;
1463}