blob: 4887e4895fd7299a3bd2b7295bfe173626ce148d [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;
Stefan Richterc868ae22007-03-14 00:26:38 +0100146 pos != NULL; pos = pos->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 if (pos->kv == kv)
148 return pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 return NULL;
150}
151
Stefan Richter6c88e472007-03-11 22:47:34 +0100152static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100153csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
155 struct csr1212_keyval *kv;
156
Stefan Richterc868ae22007-03-14 00:26:38 +0100157 for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 if (kv->offset == offset)
159 return kv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 return NULL;
161}
162
163
164/* Creation Routines */
Stefan Richter6c88e472007-03-11 22:47:34 +0100165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
167 size_t bus_info_size, void *private)
168{
169 struct csr1212_csr *csr;
170
171 csr = CSR1212_MALLOC(sizeof(*csr));
172 if (!csr)
173 return NULL;
174
175 csr->cache_head =
176 csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
177 CSR1212_CONFIG_ROM_SPACE_SIZE);
178 if (!csr->cache_head) {
179 CSR1212_FREE(csr);
180 return NULL;
181 }
182
183 /* The keyval key id is not used for the root node, but a valid key id
184 * that can be used for a directory needs to be passed to
185 * csr1212_new_directory(). */
186 csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
187 if (!csr->root_kv) {
188 CSR1212_FREE(csr->cache_head);
189 CSR1212_FREE(csr);
190 return NULL;
191 }
192
193 csr->bus_info_data = csr->cache_head->data;
194 csr->bus_info_len = bus_info_size;
195 csr->crc_len = bus_info_size;
196 csr->ops = ops;
197 csr->private = private;
198 csr->cache_tail = csr->cache_head;
199
200 return csr;
201}
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203void csr1212_init_local_csr(struct csr1212_csr *csr,
Stefan Richter982610b2007-03-11 22:49:34 +0100204 const u32 *bus_info_data, int max_rom)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
206 static const int mr_map[] = { 4, 64, 1024, 0 };
207
Ben Collins1934b8b2005-07-09 20:01:23 -0400208 BUG_ON(max_rom & ~0x3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 csr->max_rom = mr_map[max_rom];
210 memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
211}
212
Stefan Richter982610b2007-03-11 22:49:34 +0100213static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214{
215 struct csr1212_keyval *kv;
216
217 if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
218 return NULL;
219
220 kv = CSR1212_MALLOC(sizeof(*kv));
221 if (!kv)
222 return NULL;
223
224 kv->key.type = type;
225 kv->key.id = key;
226
227 kv->associate = NULL;
228 kv->refcnt = 1;
229
230 kv->next = NULL;
231 kv->prev = NULL;
232 kv->offset = 0;
233 kv->valid = 0;
234 return kv;
235}
236
Stefan Richter982610b2007-03-11 22:49:34 +0100237struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238{
Stefan Richterc868ae22007-03-14 00:26:38 +0100239 struct csr1212_keyval *kv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Stefan Richterc868ae22007-03-14 00:26:38 +0100241 kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 if (!kv)
243 return NULL;
244
245 kv->value.immediate = value;
246 kv->valid = 1;
247 return kv;
248}
249
Stefan Richter6c88e472007-03-11 22:47:34 +0100250static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100251csr1212_new_leaf(u8 key, const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252{
Stefan Richterc868ae22007-03-14 00:26:38 +0100253 struct csr1212_keyval *kv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Stefan Richterc868ae22007-03-14 00:26:38 +0100255 kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 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{
Stefan Richterc868ae22007-03-14 00:26:38 +0100282 struct csr1212_keyval *kv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Stefan Richterc868ae22007-03-14 00:26:38 +0100284 kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 if (!kv)
286 return NULL;
287
288 kv->value.csr_offset = csr_offset;
289
290 kv->offset = 0;
291 kv->valid = 1;
292 return kv;
293}
294
Stefan Richter982610b2007-03-11 22:49:34 +0100295struct csr1212_keyval *csr1212_new_directory(u8 key)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
Stefan Richterc868ae22007-03-14 00:26:38 +0100297 struct csr1212_keyval *kv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Stefan Richterc868ae22007-03-14 00:26:38 +0100299 kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (!kv)
301 return NULL;
302
303 kv->value.directory.len = 0;
304 kv->offset = 0;
305 kv->value.directory.dentries_head = NULL;
306 kv->value.directory.dentries_tail = NULL;
307 kv->valid = 1;
308 return kv;
309}
310
Stefan Richter64ff7122007-03-11 22:50:13 +0100311void csr1212_associate_keyval(struct csr1212_keyval *kv,
312 struct csr1212_keyval *associate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
Stefan Richter64ff7122007-03-11 22:50:13 +0100314 BUG_ON(!kv || !associate || 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) ||
320 (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
Stefan Richterc868ae22007-03-14 00:26:38 +0100321 associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
Stefan Richter64ff7122007-03-11 22:50:13 +0100322 (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
323 associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
324 (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
325 kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
326 (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
327 kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 if (kv->associate)
330 csr1212_release_keyval(kv->associate);
331
332 associate->refcnt++;
333 kv->associate = associate;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
336int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
337 struct csr1212_keyval *kv)
338{
339 struct csr1212_dentry *dentry;
340
Stefan Richter64ff7122007-03-11 22:50:13 +0100341 BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 dentry = CSR1212_MALLOC(sizeof(*dentry));
344 if (!dentry)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100345 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 dentry->kv = kv;
348
349 kv->refcnt++;
350
351 dentry->next = NULL;
352 dentry->prev = dir->value.directory.dentries_tail;
353
354 if (!dir->value.directory.dentries_head)
355 dir->value.directory.dentries_head = dentry;
356
357 if (dir->value.directory.dentries_tail)
358 dir->value.directory.dentries_tail->next = dentry;
359 dir->value.directory.dentries_tail = dentry;
360
361 return CSR1212_SUCCESS;
362}
363
Stefan Richter6c88e472007-03-11 22:47:34 +0100364#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
365 (&((kv)->value.leaf.data[1]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Stefan Richter6c88e472007-03-11 22:47:34 +0100367#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
368 ((kv)->value.leaf.data[0] = \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100369 cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
370 ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
Stefan Richter6c88e472007-03-11 22:47:34 +0100371#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
372 ((kv)->value.leaf.data[0] = \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100373 cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
374 CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
375 ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Stefan Richter6c88e472007-03-11 22:47:34 +0100377static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100378csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
Stefan Richter6c88e472007-03-11 22:47:34 +0100379 const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 struct csr1212_keyval *kv;
382
383 kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
384 data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
385 if (!kv)
386 return NULL;
387
388 CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
389 CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
390
391 if (data) {
392 memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
393 }
394
395 return kv;
396}
397
Stefan Richter6c88e472007-03-11 22:47:34 +0100398#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \
399 ((kv)->value.leaf.data[1] = \
400 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100401 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \
402 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \
403 cpu_to_be32(((width) & CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \
404 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Stefan Richter6c88e472007-03-11 22:47:34 +0100406#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \
407 ((kv)->value.leaf.data[1] = \
408 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100409 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \
410 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \
411 cpu_to_be32(((char_set) & \
412 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \
413 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))
Stefan Richter6c88e472007-03-11 22:47:34 +0100414
415#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
416 ((kv)->value.leaf.data[1] = \
417 ((kv)->value.leaf.data[1] & \
Stefan Richter7fb9add2007-03-11 22:49:05 +0100418 cpu_to_be32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
419 cpu_to_be32(((language) & \
420 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
Stefan Richter6c88e472007-03-11 22:47:34 +0100421
422static struct csr1212_keyval *
Stefan Richter982610b2007-03-11 22:49:34 +0100423csr1212_new_textual_descriptor_leaf(u8 cwidth, u16 cset, u16 language,
424 const void *data, size_t data_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425{
426 struct csr1212_keyval *kv;
427 char *lstr;
428
429 kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len +
430 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
431 if (!kv)
432 return NULL;
433
434 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth);
435 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset);
436 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
437
438 lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
439
440 /* make sure last quadlet is zeroed out */
Stefan Richter982610b2007-03-11 22:49:34 +0100441 *((u32*)&(lstr[(data_len - 1) & ~0x3])) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 /* don't copy the NUL terminator */
444 memcpy(lstr, data, data_len);
445
446 return kv;
447}
448
449static int csr1212_check_minimal_ascii(const char *s)
450{
451 static const char minimal_ascii_table[] = {
452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
453 0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00,
454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
456 0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27,
457 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
458 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
459 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
460 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
461 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
462 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
463 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
464 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
465 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
466 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
467 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
468 };
469 for (; *s; s++) {
470 if (minimal_ascii_table[*s & 0x7F] != *s)
471 return -1; /* failed */
472 }
473 /* String conforms to minimal-ascii, as specified by IEEE 1212,
474 * par. 7.4 */
475 return 0;
476}
477
478struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
479{
480 /* Check if string conform to minimal_ascii format */
481 if (csr1212_check_minimal_ascii(s))
482 return NULL;
483
484 /* IEEE 1212, par. 7.5.4.1 Textual descriptors (minimal ASCII) */
485 return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s));
486}
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489/* Destruction Routines */
490
491void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
492 struct csr1212_keyval *kv)
493{
494 struct csr1212_dentry *dentry;
495
496 if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
497 return;
498
499 dentry = csr1212_find_keyval(dir, kv);
500
501 if (!dentry)
502 return;
503
504 if (dentry->prev)
505 dentry->prev->next = dentry->next;
506 if (dentry->next)
507 dentry->next->prev = dentry->prev;
508 if (dir->value.directory.dentries_head == dentry)
509 dir->value.directory.dentries_head = dentry->next;
510 if (dir->value.directory.dentries_tail == dentry)
511 dir->value.directory.dentries_tail = dentry->prev;
512
513 CSR1212_FREE(dentry);
514
515 csr1212_release_keyval(kv);
516}
517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518/* This function is used to free the memory taken by a keyval. If the given
519 * keyval is a directory type, then any keyvals contained in that directory
520 * will be destroyed as well if their respective refcnts are 0. By means of
521 * list manipulation, this routine will descend a directory structure in a
522 * non-recursive manner. */
Stefan Richterc1a37f22007-03-14 00:20:53 +0100523static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
525 struct csr1212_keyval *k, *a;
526 struct csr1212_dentry dentry;
527 struct csr1212_dentry *head, *tail;
528
529 dentry.kv = kv;
530 dentry.next = NULL;
531 dentry.prev = NULL;
532
533 head = &dentry;
534 tail = head;
535
536 while (head) {
537 k = head->kv;
538
539 while (k) {
540 k->refcnt--;
541
542 if (k->refcnt > 0)
543 break;
544
545 a = k->associate;
546
547 if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
Stefan Richterc868ae22007-03-14 00:26:38 +0100548 /* If the current entry is a directory, move all
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 * the entries to the destruction list. */
550 if (k->value.directory.dentries_head) {
Stefan Richterc868ae22007-03-14 00:26:38 +0100551 tail->next =
552 k->value.directory.dentries_head;
553 k->value.directory.dentries_head->prev =
554 tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 tail = k->value.directory.dentries_tail;
556 }
557 }
558 free_keyval(k);
559 k = a;
560 }
561
562 head = head->next;
563 if (head) {
Stefan Richterc868ae22007-03-14 00:26:38 +0100564 if (head->prev && head->prev != &dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 CSR1212_FREE(head->prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 head->prev = NULL;
Stefan Richterc868ae22007-03-14 00:26:38 +0100567 } else if (tail != &dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 CSR1212_FREE(tail);
Stefan Richterc868ae22007-03-14 00:26:38 +0100569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
571}
572
Stefan Richterc1a37f22007-03-14 00:20:53 +0100573void csr1212_release_keyval(struct csr1212_keyval *kv)
574{
575 if (kv->refcnt > 1)
576 kv->refcnt--;
577 else
578 csr1212_destroy_keyval(kv);
579}
580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581void csr1212_destroy_csr(struct csr1212_csr *csr)
582{
583 struct csr1212_csr_rom_cache *c, *oc;
584 struct csr1212_cache_region *cr, *ocr;
585
586 csr1212_release_keyval(csr->root_kv);
587
588 c = csr->cache_head;
589 while (c) {
590 oc = c;
591 cr = c->filled_head;
592 while (cr) {
593 ocr = cr;
594 cr = cr->next;
595 CSR1212_FREE(ocr);
596 }
597 c = c->next;
598 CSR1212_FREE(oc);
599 }
600
601 CSR1212_FREE(csr);
602}
603
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605/* CSR Image Creation */
606
607static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
608{
609 struct csr1212_csr_rom_cache *cache;
Stefan Richter982610b2007-03-11 22:49:34 +0100610 u64 csr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
Stefan Richter64ff7122007-03-11 22:50:13 +0100612 BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
613 !csr->ops->release_addr || csr->max_rom < 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 /* ROM size must be a multiple of csr->max_rom */
616 romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
617
Stefan Richterc868ae22007-03-14 00:26:38 +0100618 csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
619 csr->private);
620 if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
Stefan Richter7fb9add2007-03-11 22:49:05 +0100621 return -ENOMEM;
Stefan Richterc868ae22007-03-14 00:26:38 +0100622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
624 /* Invalid address returned from allocate_addr_range(). */
625 csr->ops->release_addr(csr_addr, csr->private);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100626 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
628
Stefan Richterc868ae22007-03-14 00:26:38 +0100629 cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
630 romsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if (!cache) {
632 csr->ops->release_addr(csr_addr, csr->private);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100633 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
635
Stefan Richterc868ae22007-03-14 00:26:38 +0100636 cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
637 CSR1212_KV_ID_EXTENDED_ROM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (!cache->ext_rom) {
639 csr->ops->release_addr(csr_addr, csr->private);
640 CSR1212_FREE(cache);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100641 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 }
643
Stefan Richterc868ae22007-03-14 00:26:38 +0100644 if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
645 CSR1212_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 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) {
Stefan Richterc868ae22007-03-14 00:26:38 +0100676 csr1212_detach_keyval_from_directory(csr->root_kv,
677 cache->ext_rom);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 csr1212_release_keyval(cache->ext_rom);
679 }
680
681 CSR1212_FREE(cache);
682}
683
684static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
685 struct csr1212_keyval **layout_tail)
686{
687 struct csr1212_dentry *dentry;
688 struct csr1212_keyval *dkv;
689 struct csr1212_keyval *last_extkey_spec = NULL;
690 struct csr1212_keyval *last_extkey = NULL;
691 int num_entries = 0;
692
693 for (dentry = dir->value.directory.dentries_head; dentry;
694 dentry = dentry->next) {
695 for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
696 /* Special Case: Extended Key Specifier_ID */
Stefan Richterc868ae22007-03-14 00:26:38 +0100697 if (dkv->key.id ==
698 CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
699 if (last_extkey_spec == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 last_extkey_spec = dkv;
Stefan Richterc868ae22007-03-14 00:26:38 +0100701 else if (dkv->value.immediate !=
702 last_extkey_spec->value.immediate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 last_extkey_spec = dkv;
Stefan Richterc868ae22007-03-14 00:26:38 +0100704 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 /* Special Case: Extended Key */
707 } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
Stefan Richterc868ae22007-03-14 00:26:38 +0100708 if (last_extkey == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 last_extkey = dkv;
Stefan Richterc868ae22007-03-14 00:26:38 +0100710 else if (dkv->value.immediate !=
711 last_extkey->value.immediate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 last_extkey = dkv;
Stefan Richterc868ae22007-03-14 00:26:38 +0100713 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716
717 num_entries += 1;
718
Stefan Richterc868ae22007-03-14 00:26:38 +0100719 switch (dkv->key.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 default:
721 case CSR1212_KV_TYPE_IMMEDIATE:
722 case CSR1212_KV_TYPE_CSR_OFFSET:
723 break;
724 case CSR1212_KV_TYPE_LEAF:
725 case CSR1212_KV_TYPE_DIRECTORY:
726 /* Remove from list */
727 if (dkv->prev && (dkv->prev->next == dkv))
728 dkv->prev->next = dkv->next;
729 if (dkv->next && (dkv->next->prev == dkv))
730 dkv->next->prev = dkv->prev;
731 //if (dkv == *layout_tail)
732 // *layout_tail = dkv->prev;
733
734 /* Special case: Extended ROM leafs */
735 if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
736 dkv->value.leaf.len = -1;
Stefan Richterc868ae22007-03-14 00:26:38 +0100737 /* Don't add Extended ROM leafs in the
738 * layout list, they are handled
739 * differently. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 break;
741 }
742
743 /* Add to tail of list */
744 dkv->next = NULL;
745 dkv->prev = *layout_tail;
746 (*layout_tail)->next = dkv;
747 *layout_tail = dkv;
748 break;
749 }
750 }
751 }
752 return num_entries;
753}
754
Stefan Richter6c88e472007-03-11 22:47:34 +0100755static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
757 struct csr1212_keyval *ltail = kv;
758 size_t agg_size = 0;
759
Stefan Richterc868ae22007-03-14 00:26:38 +0100760 while (kv) {
761 switch (kv->key.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 case CSR1212_KV_TYPE_LEAF:
763 /* Add 1 quadlet for crc/len field */
764 agg_size += kv->value.leaf.len + 1;
765 break;
766
767 case CSR1212_KV_TYPE_DIRECTORY:
Stefan Richterc868ae22007-03-14 00:26:38 +0100768 kv->value.directory.len =
769 csr1212_generate_layout_subdir(kv, &ltail);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 /* Add 1 quadlet for crc/len field */
771 agg_size += kv->value.directory.len + 1;
772 break;
773 }
774 kv = kv->next;
775 }
776 return quads_to_bytes(agg_size);
777}
778
Stefan Richter6c88e472007-03-11 22:47:34 +0100779static struct csr1212_keyval *
780csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
781 struct csr1212_keyval *start_kv, int start_pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782{
783 struct csr1212_keyval *kv = start_kv;
784 struct csr1212_keyval *okv = start_kv;
785 int pos = start_pos;
786 int kv_len = 0, okv_len = 0;
787
788 cache->layout_head = kv;
789
Stefan Richterc868ae22007-03-14 00:26:38 +0100790 while (kv && pos < cache->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 /* Special case: Extended ROM leafs */
Stefan Richterc868ae22007-03-14 00:26:38 +0100792 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 kv->offset = cache->offset + pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Stefan Richterc868ae22007-03-14 00:26:38 +0100795 switch (kv->key.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 case CSR1212_KV_TYPE_LEAF:
797 kv_len = kv->value.leaf.len;
798 break;
799
800 case CSR1212_KV_TYPE_DIRECTORY:
801 kv_len = kv->value.directory.len;
802 break;
803
804 default:
805 /* Should never get here */
806 break;
807 }
808
809 pos += quads_to_bytes(kv_len + 1);
810
811 if (pos <= cache->size) {
812 okv = kv;
813 okv_len = kv_len;
814 kv = kv->next;
815 }
816 }
817
818 cache->layout_tail = okv;
Stefan Richterc868ae22007-03-14 00:26:38 +0100819 cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 return kv;
822}
823
Stefan Richter6c88e472007-03-11 22:47:34 +0100824#define CSR1212_KV_KEY_SHIFT 24
825#define CSR1212_KV_KEY_TYPE_SHIFT 6
826#define CSR1212_KV_KEY_ID_MASK 0x3f
827#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */
828
829static void
Stefan Richter982610b2007-03-11 22:49:34 +0100830csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
832 struct csr1212_dentry *dentry;
833 struct csr1212_keyval *last_extkey_spec = NULL;
834 struct csr1212_keyval *last_extkey = NULL;
835 int index = 0;
836
Stefan Richterc868ae22007-03-14 00:26:38 +0100837 for (dentry = dir->value.directory.dentries_head;
838 dentry;
839 dentry = dentry->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 struct csr1212_keyval *a;
841
842 for (a = dentry->kv; a; a = a->associate) {
Stefan Richter982610b2007-03-11 22:49:34 +0100843 u32 value = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 /* Special Case: Extended Key Specifier_ID */
Stefan Richterc868ae22007-03-14 00:26:38 +0100846 if (a->key.id ==
847 CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
848 if (last_extkey_spec == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 last_extkey_spec = a;
Stefan Richterc868ae22007-03-14 00:26:38 +0100850 else if (a->value.immediate !=
851 last_extkey_spec->value.immediate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 last_extkey_spec = a;
Stefan Richterc868ae22007-03-14 00:26:38 +0100853 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 continue;
Stefan Richterc868ae22007-03-14 00:26:38 +0100855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 /* Special Case: Extended Key */
857 } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
Stefan Richterc868ae22007-03-14 00:26:38 +0100858 if (last_extkey == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 last_extkey = a;
Stefan Richterc868ae22007-03-14 00:26:38 +0100860 else if (a->value.immediate !=
861 last_extkey->value.immediate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 last_extkey = a;
Stefan Richterc868ae22007-03-14 00:26:38 +0100863 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 }
866
Stefan Richterc868ae22007-03-14 00:26:38 +0100867 switch (a->key.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 case CSR1212_KV_TYPE_IMMEDIATE:
869 value = a->value.immediate;
870 break;
871 case CSR1212_KV_TYPE_CSR_OFFSET:
872 value = a->value.csr_offset;
873 break;
874 case CSR1212_KV_TYPE_LEAF:
875 value = a->offset;
876 value -= dir->offset + quads_to_bytes(1+index);
877 value = bytes_to_quads(value);
878 break;
879 case CSR1212_KV_TYPE_DIRECTORY:
880 value = a->offset;
881 value -= dir->offset + quads_to_bytes(1+index);
882 value = bytes_to_quads(value);
883 break;
884 default:
885 /* Should never get here */
886 break; /* GDB breakpoint */
887 }
888
Stefan Richterc868ae22007-03-14 00:26:38 +0100889 value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
890 CSR1212_KV_KEY_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
Stefan Richterc868ae22007-03-14 00:26:38 +0100892 (CSR1212_KV_KEY_SHIFT +
893 CSR1212_KV_KEY_TYPE_SHIFT);
Stefan Richter7fb9add2007-03-11 22:49:05 +0100894 data_buffer[index] = cpu_to_be32(value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 index++;
896 }
897 }
898}
899
Stefan Richter6c88e472007-03-11 22:47:34 +0100900struct csr1212_keyval_img {
Stefan Richter982610b2007-03-11 22:49:34 +0100901 u16 length;
902 u16 crc;
Stefan Richter6c88e472007-03-11 22:47:34 +0100903
904 /* Must be last */
Stefan Richter982610b2007-03-11 22:49:34 +0100905 u32 data[0]; /* older gcc can't handle [] which is standard */
Stefan Richter6c88e472007-03-11 22:47:34 +0100906};
907
908static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909{
910 struct csr1212_keyval *kv, *nkv;
911 struct csr1212_keyval_img *kvi;
912
Stefan Richterc868ae22007-03-14 00:26:38 +0100913 for (kv = cache->layout_head;
914 kv != cache->layout_tail->next;
915 kv = nkv) {
916 kvi = (struct csr1212_keyval_img *)(cache->data +
917 bytes_to_quads(kv->offset - cache->offset));
918 switch (kv->key.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 default:
920 case CSR1212_KV_TYPE_IMMEDIATE:
921 case CSR1212_KV_TYPE_CSR_OFFSET:
922 /* Should never get here */
923 break; /* GDB breakpoint */
924
925 case CSR1212_KV_TYPE_LEAF:
926 /* Don't copy over Extended ROM areas, they are
927 * already filled out! */
928 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
929 memcpy(kvi->data, kv->value.leaf.data,
930 quads_to_bytes(kv->value.leaf.len));
931
Stefan Richter7fb9add2007-03-11 22:49:05 +0100932 kvi->length = cpu_to_be16(kv->value.leaf.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
934 break;
935
936 case CSR1212_KV_TYPE_DIRECTORY:
937 csr1212_generate_tree_subdir(kv, kvi->data);
938
Stefan Richter7fb9add2007-03-11 22:49:05 +0100939 kvi->length = cpu_to_be16(kv->value.directory.len);
Stefan Richterc868ae22007-03-14 00:26:38 +0100940 kvi->crc = csr1212_crc16(kvi->data,
941 kv->value.directory.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 break;
943 }
944
945 nkv = kv->next;
946 if (kv->prev)
947 kv->prev->next = NULL;
948 if (kv->next)
949 kv->next->prev = NULL;
950 kv->prev = NULL;
951 kv->next = NULL;
952 }
953}
954
Stefan Richterfd2f3bd2007-03-11 22:51:24 +0100955/* This size is arbitrarily chosen.
956 * The struct overhead is subtracted for more economic allocations. */
957#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
Stefan Richter6c88e472007-03-11 22:47:34 +0100958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959int csr1212_generate_csr_image(struct csr1212_csr *csr)
960{
961 struct csr1212_bus_info_block_img *bi;
962 struct csr1212_csr_rom_cache *cache;
963 struct csr1212_keyval *kv;
964 size_t agg_size;
965 int ret;
966 int init_offset;
967
Stefan Richter64ff7122007-03-11 22:50:13 +0100968 BUG_ON(!csr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970 cache = csr->cache_head;
971
972 bi = (struct csr1212_bus_info_block_img*)cache->data;
973
974 bi->length = bytes_to_quads(csr->bus_info_len) - 1;
975 bi->crc_length = bi->length;
976 bi->crc = csr1212_crc16(bi->data, bi->crc_length);
977
978 csr->root_kv->next = NULL;
979 csr->root_kv->prev = NULL;
980
981 agg_size = csr1212_generate_layout_order(csr->root_kv);
982
983 init_offset = csr->bus_info_len;
984
Stefan Richterc868ae22007-03-14 00:26:38 +0100985 for (kv = csr->root_kv, cache = csr->cache_head;
986 kv;
987 cache = cache->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (!cache) {
989 /* Estimate approximate number of additional cache
990 * regions needed (it assumes that the cache holding
991 * the first 1K Config ROM space always exists). */
992 int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
Stefan Richter982610b2007-03-11 22:49:34 +0100993 (2 * sizeof(u32))) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 /* Add additional cache regions, extras will be
996 * removed later */
997 for (; est_c; est_c--) {
Stefan Richterc868ae22007-03-14 00:26:38 +0100998 ret = csr1212_append_new_cache(csr,
999 CSR1212_EXTENDED_ROM_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (ret != CSR1212_SUCCESS)
1001 return ret;
1002 }
1003 /* Need to re-layout for additional cache regions */
1004 agg_size = csr1212_generate_layout_order(csr->root_kv);
1005 kv = csr->root_kv;
1006 cache = csr->cache_head;
1007 init_offset = csr->bus_info_len;
1008 }
1009 kv = csr1212_generate_positions(cache, kv, init_offset);
1010 agg_size -= cache->len;
Stefan Richter982610b2007-03-11 22:49:34 +01001011 init_offset = sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 }
1013
1014 /* Remove unused, excess cache regions */
1015 while (cache) {
1016 struct csr1212_csr_rom_cache *oc = cache;
1017
1018 cache = cache->next;
1019 csr1212_remove_cache(csr, oc);
1020 }
1021
1022 /* Go through the list backward so that when done, the correct CRC
1023 * will be calculated for the Extended ROM areas. */
Stefan Richterc868ae22007-03-14 00:26:38 +01001024 for (cache = csr->cache_tail; cache; cache = cache->prev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 /* Only Extended ROM caches should have this set. */
1026 if (cache->ext_rom) {
1027 int leaf_size;
1028
1029 /* Make sure the Extended ROM leaf is a multiple of
1030 * max_rom in size. */
Stefan Richter64ff7122007-03-11 22:50:13 +01001031 BUG_ON(csr->max_rom < 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 leaf_size = (cache->len + (csr->max_rom - 1)) &
1033 ~(csr->max_rom - 1);
1034
1035 /* Zero out the unused ROM region */
1036 memset(cache->data + bytes_to_quads(cache->len), 0x00,
1037 leaf_size - cache->len);
1038
1039 /* Subtract leaf header */
Stefan Richter982610b2007-03-11 22:49:34 +01001040 leaf_size -= sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 /* Update the Extended ROM leaf length */
1043 cache->ext_rom->value.leaf.len =
1044 bytes_to_quads(leaf_size);
1045 } else {
1046 /* Zero out the unused ROM region */
1047 memset(cache->data + bytes_to_quads(cache->len), 0x00,
1048 cache->size - cache->len);
1049 }
1050
1051 /* Copy the data into the cache buffer */
1052 csr1212_fill_cache(cache);
1053
1054 if (cache != csr->cache_head) {
1055 /* Set the length and CRC of the extended ROM. */
1056 struct csr1212_keyval_img *kvi =
1057 (struct csr1212_keyval_img*)cache->data;
Stefan Richter982610b2007-03-11 22:49:34 +01001058 u16 len = bytes_to_quads(cache->len) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Stefan Richter7fb9add2007-03-11 22:49:05 +01001060 kvi->length = cpu_to_be16(len);
1061 kvi->crc = csr1212_crc16(kvi->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
1063 }
1064
1065 return CSR1212_SUCCESS;
1066}
1067
Stefan Richter982610b2007-03-11 22:49:34 +01001068int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
1070 struct csr1212_csr_rom_cache *cache;
1071
Stefan Richterc868ae22007-03-14 00:26:38 +01001072 for (cache = csr->cache_head; cache; cache = cache->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 if (offset >= cache->offset &&
1074 (offset + len) <= (cache->offset + cache->size)) {
Stefan Richterc868ae22007-03-14 00:26:38 +01001075 memcpy(buffer, &cache->data[
1076 bytes_to_quads(offset - cache->offset)],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 len);
1078 return CSR1212_SUCCESS;
1079 }
Stefan Richterc868ae22007-03-14 00:26:38 +01001080
Stefan Richter7fb9add2007-03-11 22:49:05 +01001081 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082}
1083
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085/* Parse a chunk of data as a Config ROM */
1086
1087static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
1088{
1089 struct csr1212_bus_info_block_img *bi;
1090 struct csr1212_cache_region *cr;
1091 int i;
1092 int ret;
1093
1094 /* IEEE 1212 says that the entire bus info block should be readable in
1095 * a single transaction regardless of the max_rom value.
1096 * Unfortunately, many IEEE 1394 devices do not abide by that, so the
1097 * bus info block will be read 1 quadlet at a time. The rest of the
1098 * ConfigROM will be read according to the max_rom field. */
Stefan Richter982610b2007-03-11 22:49:34 +01001099 for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
Stefan Richterc868ae22007-03-14 00:26:38 +01001101 sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
1102 csr->private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 if (ret != CSR1212_SUCCESS)
1104 return ret;
Stefan Richterb2051f82007-01-03 19:32:13 +01001105
1106 /* check ROM header's info_length */
1107 if (i == 0 &&
Stefan Richter7fb9add2007-03-11 22:49:05 +01001108 be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
Stefan Richterb2051f82007-01-03 19:32:13 +01001109 bytes_to_quads(csr->bus_info_len) - 1)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001110 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
1112
1113 bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
1114 csr->crc_len = quads_to_bytes(bi->crc_length);
1115
Stefan Richterc868ae22007-03-14 00:26:38 +01001116 /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
1117 * is not always the case, so read the rest of the crc area 1 quadlet at
1118 * a time. */
Stefan Richter982610b2007-03-11 22:49:34 +01001119 for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
Stefan Richterc868ae22007-03-14 00:26:38 +01001121 sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
1122 csr->private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 if (ret != CSR1212_SUCCESS)
1124 return ret;
1125 }
1126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127#if 0
1128 /* Apparently there are too many differnt wrong implementations of the
1129 * CRC algorithm that verifying them is moot. */
1130 if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
1131 (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
Stefan Richter7fb9add2007-03-11 22:49:05 +01001132 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133#endif
1134
Stefan Richter85511582005-11-07 06:31:45 -05001135 cr = CSR1212_MALLOC(sizeof(*cr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 if (!cr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001137 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
1139 cr->next = NULL;
1140 cr->prev = NULL;
1141 cr->offset_start = 0;
1142 cr->offset_end = csr->crc_len + 4;
1143
1144 csr->cache_head->filled_head = cr;
1145 csr->cache_head->filled_tail = cr;
1146
1147 return CSR1212_SUCCESS;
1148}
1149
Stefan Richter7fb9add2007-03-11 22:49:05 +01001150#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
Stefan Richter6c88e472007-03-11 22:47:34 +01001151#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
1152#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
1153#define CSR1212_KV_VAL_MASK 0xffffff
Stefan Richter7fb9add2007-03-11 22:49:05 +01001154#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
Stefan Richter6c88e472007-03-11 22:47:34 +01001155
Stefan Richterc868ae22007-03-14 00:26:38 +01001156static int
1157csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158{
1159 int ret = CSR1212_SUCCESS;
1160 struct csr1212_keyval *k = NULL;
Stefan Richter982610b2007-03-11 22:49:34 +01001161 u32 offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Stefan Richterc868ae22007-03-14 00:26:38 +01001163 switch (CSR1212_KV_KEY_TYPE(ki)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 case CSR1212_KV_TYPE_IMMEDIATE:
1165 k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
1166 CSR1212_KV_VAL(ki));
1167 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001168 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 goto fail;
1170 }
1171
1172 k->refcnt = 0; /* Don't keep local reference when parsing. */
1173 break;
1174
1175 case CSR1212_KV_TYPE_CSR_OFFSET:
1176 k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
1177 CSR1212_KV_VAL(ki));
1178 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001179 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 goto fail;
1181 }
1182 k->refcnt = 0; /* Don't keep local reference when parsing. */
1183 break;
1184
1185 default:
1186 /* Compute the offset from 0xffff f000 0000. */
1187 offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
1188 if (offset == kv_pos) {
1189 /* Uh-oh. Can't have a relative offset of 0 for Leaves
1190 * or Directories. The Config ROM image is most likely
1191 * messed up, so we'll just abort here. */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001192 ret = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 goto fail;
1194 }
1195
1196 k = csr1212_find_keyval_offset(dir, offset);
1197
1198 if (k)
1199 break; /* Found it. */
1200
Stefan Richterc868ae22007-03-14 00:26:38 +01001201 if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
Stefan Richterc868ae22007-03-14 00:26:38 +01001203 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
Stefan Richterc868ae22007-03-14 00:26:38 +01001205
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 if (!k) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001207 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 goto fail;
1209 }
1210 k->refcnt = 0; /* Don't keep local reference when parsing. */
1211 k->valid = 0; /* Contents not read yet so it's not valid. */
1212 k->offset = offset;
1213
1214 k->prev = dir;
1215 k->next = dir->next;
1216 dir->next->prev = k;
1217 dir->next = k;
1218 }
1219 ret = csr1212_attach_keyval_to_directory(dir, k);
1220
1221fail:
Stefan Richter6c88e472007-03-11 22:47:34 +01001222 if (ret != CSR1212_SUCCESS && k != NULL)
1223 free_keyval(k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 return ret;
1225}
1226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227int csr1212_parse_keyval(struct csr1212_keyval *kv,
1228 struct csr1212_csr_rom_cache *cache)
1229{
1230 struct csr1212_keyval_img *kvi;
1231 int i;
1232 int ret = CSR1212_SUCCESS;
1233 int kvi_len;
1234
Stefan Richterc868ae22007-03-14 00:26:38 +01001235 kvi = (struct csr1212_keyval_img*)
1236 &cache->data[bytes_to_quads(kv->offset - cache->offset)];
Stefan Richter7fb9add2007-03-11 22:49:05 +01001237 kvi_len = be16_to_cpu(kvi->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239#if 0
1240 /* Apparently there are too many differnt wrong implementations of the
1241 * CRC algorithm that verifying them is moot. */
1242 if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
1243 (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001244 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 goto fail;
1246 }
1247#endif
1248
Stefan Richterc868ae22007-03-14 00:26:38 +01001249 switch (kv->key.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 case CSR1212_KV_TYPE_DIRECTORY:
1251 for (i = 0; i < kvi_len; i++) {
Stefan Richter982610b2007-03-11 22:49:34 +01001252 u32 ki = kvi->data[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 /* Some devices put null entries in their unit
1255 * directories. If we come across such an entry,
1256 * then skip it. */
1257 if (ki == 0x0)
1258 continue;
1259 ret = csr1212_parse_dir_entry(kv, ki,
Stefan Richterc868ae22007-03-14 00:26:38 +01001260 kv->offset + quads_to_bytes(i + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 }
1262 kv->value.directory.len = kvi_len;
1263 break;
1264
1265 case CSR1212_KV_TYPE_LEAF:
1266 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
Stefan Richterc868ae22007-03-14 00:26:38 +01001267 size_t size = quads_to_bytes(kvi_len);
1268
1269 kv->value.leaf.data = CSR1212_MALLOC(size);
Stefan Richter85511582005-11-07 06:31:45 -05001270 if (!kv->value.leaf.data) {
Stefan Richter7fb9add2007-03-11 22:49:05 +01001271 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 goto fail;
1273 }
1274
1275 kv->value.leaf.len = kvi_len;
Stefan Richterc868ae22007-03-14 00:26:38 +01001276 memcpy(kv->value.leaf.data, kvi->data, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 }
1278 break;
1279 }
1280
1281 kv->valid = 1;
1282
1283fail:
1284 return ret;
1285}
1286
Stefan Richterc1a37f22007-03-14 00:20:53 +01001287static int
1288csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
1290 struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
1291 struct csr1212_keyval_img *kvi = NULL;
1292 struct csr1212_csr_rom_cache *cache;
1293 int cache_index;
Stefan Richter982610b2007-03-11 22:49:34 +01001294 u64 addr;
1295 u32 *cache_ptr;
1296 u16 kv_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Stefan Richter64ff7122007-03-11 22:50:13 +01001298 BUG_ON(!csr || !kv || csr->max_rom < 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 /* First find which cache the data should be in (or go in if not read
1301 * yet). */
Stefan Richterc868ae22007-03-14 00:26:38 +01001302 for (cache = csr->cache_head; cache; cache = cache->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if (kv->offset >= cache->offset &&
1304 kv->offset < (cache->offset + cache->size))
1305 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
1307 if (!cache) {
Stefan Richter982610b2007-03-11 22:49:34 +01001308 u32 q, cache_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
1310 /* Only create a new cache for Extended ROM leaves. */
1311 if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001312 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
1314 if (csr->ops->bus_read(csr,
1315 CSR1212_REGISTER_SPACE_BASE + kv->offset,
Stefan Richterc868ae22007-03-14 00:26:38 +01001316 sizeof(u32), &q, csr->private))
Stefan Richter7fb9add2007-03-11 22:49:05 +01001317 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
Stefan Richter7fb9add2007-03-11 22:49:05 +01001319 kv->value.leaf.len = be32_to_cpu(q) >> 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
1321 cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
1322 (csr->max_rom - 1)) & ~(csr->max_rom - 1);
1323
1324 cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
1325 if (!cache)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001326 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
1328 kv->value.leaf.data = &cache->data[1];
1329 csr->cache_tail->next = cache;
1330 cache->prev = csr->cache_tail;
1331 cache->next = NULL;
1332 csr->cache_tail = cache;
1333 cache->filled_head =
Stefan Richter85511582005-11-07 06:31:45 -05001334 CSR1212_MALLOC(sizeof(*cache->filled_head));
Stefan Richterc868ae22007-03-14 00:26:38 +01001335 if (!cache->filled_head)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001336 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 cache->filled_head->offset_start = 0;
Stefan Richter982610b2007-03-11 22:49:34 +01001339 cache->filled_head->offset_end = sizeof(u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 cache->filled_tail = cache->filled_head;
1341 cache->filled_head->next = NULL;
1342 cache->filled_head->prev = NULL;
1343 cache->data[0] = q;
1344
1345 /* Don't read the entire extended ROM now. Pieces of it will
1346 * be read when entries inside it are read. */
1347 return csr1212_parse_keyval(kv, cache);
1348 }
1349
1350 cache_index = kv->offset - cache->offset;
1351
1352 /* Now seach read portions of the cache to see if it is there. */
1353 for (cr = cache->filled_head; cr; cr = cr->next) {
1354 if (cache_index < cr->offset_start) {
Stefan Richter85511582005-11-07 06:31:45 -05001355 newcr = CSR1212_MALLOC(sizeof(*newcr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 if (!newcr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001357 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
1359 newcr->offset_start = cache_index & ~(csr->max_rom - 1);
1360 newcr->offset_end = newcr->offset_start;
1361 newcr->next = cr;
1362 newcr->prev = cr->prev;
1363 cr->prev = newcr;
1364 cr = newcr;
1365 break;
1366 } else if ((cache_index >= cr->offset_start) &&
1367 (cache_index < cr->offset_end)) {
1368 kvi = (struct csr1212_keyval_img*)
1369 (&cache->data[bytes_to_quads(cache_index)]);
Stefan Richter7fb9add2007-03-11 22:49:05 +01001370 kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 break;
Stefan Richterc868ae22007-03-14 00:26:38 +01001372 } else if (cache_index == cr->offset_end) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 break;
Stefan Richterc868ae22007-03-14 00:26:38 +01001374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 }
1376
1377 if (!cr) {
1378 cr = cache->filled_tail;
Stefan Richter85511582005-11-07 06:31:45 -05001379 newcr = CSR1212_MALLOC(sizeof(*newcr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (!newcr)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001381 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 newcr->offset_start = cache_index & ~(csr->max_rom - 1);
1384 newcr->offset_end = newcr->offset_start;
1385 newcr->prev = cr;
1386 newcr->next = cr->next;
1387 cr->next = newcr;
1388 cr = newcr;
1389 cache->filled_tail = newcr;
1390 }
1391
1392 while(!kvi || cr->offset_end < cache_index + kv_len) {
1393 cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
1394 ~(csr->max_rom - 1))];
1395
1396 addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
1397 cr->offset_end) & ~(csr->max_rom - 1);
1398
1399 if (csr->ops->bus_read(csr, addr, csr->max_rom, cache_ptr,
1400 csr->private)) {
1401 if (csr->max_rom == 4)
1402 /* We've got problems! */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001403 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
1405 /* Apperently the max_rom value was a lie, set it to
1406 * do quadlet reads and try again. */
1407 csr->max_rom = 4;
1408 continue;
1409 }
1410
1411 cr->offset_end += csr->max_rom - (cr->offset_end &
1412 (csr->max_rom - 1));
1413
1414 if (!kvi && (cr->offset_end > cache_index)) {
1415 kvi = (struct csr1212_keyval_img*)
1416 (&cache->data[bytes_to_quads(cache_index)]);
Stefan Richter7fb9add2007-03-11 22:49:05 +01001417 kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 }
1419
1420 if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
1421 /* The Leaf or Directory claims its length extends
1422 * beyond the ConfigROM image region and thus beyond the
1423 * end of our cache region. Therefore, we abort now
1424 * rather than seg faulting later. */
Stefan Richter7fb9add2007-03-11 22:49:05 +01001425 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 }
1427
1428 ncr = cr->next;
1429
1430 if (ncr && (cr->offset_end >= ncr->offset_start)) {
1431 /* consolidate region entries */
1432 ncr->offset_start = cr->offset_start;
1433
1434 if (cr->prev)
1435 cr->prev->next = cr->next;
1436 ncr->prev = cr->prev;
1437 if (cache->filled_head == cr)
1438 cache->filled_head = ncr;
1439 CSR1212_FREE(cr);
1440 cr = ncr;
1441 }
1442 }
1443
1444 return csr1212_parse_keyval(kv, cache);
1445}
1446
Stefan Richterc1a37f22007-03-14 00:20:53 +01001447struct csr1212_keyval *
1448csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
1449{
1450 if (!kv)
1451 return NULL;
1452 if (!kv->valid)
1453 if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
1454 return NULL;
1455 return kv;
1456}
1457
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458int csr1212_parse_csr(struct csr1212_csr *csr)
1459{
1460 static const int mr_map[] = { 4, 64, 1024, 0 };
1461 struct csr1212_dentry *dentry;
1462 int ret;
1463
Stefan Richter64ff7122007-03-11 22:50:13 +01001464 BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
1466 ret = csr1212_parse_bus_info_block(csr);
1467 if (ret != CSR1212_SUCCESS)
1468 return ret;
1469
Stefan Richterc868ae22007-03-14 00:26:38 +01001470 if (!csr->ops->get_max_rom) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 csr->max_rom = mr_map[0]; /* default value */
Stefan Richterc868ae22007-03-14 00:26:38 +01001472 } else {
Ben Collins1934b8b2005-07-09 20:01:23 -04001473 int i = csr->ops->get_max_rom(csr->bus_info_data,
1474 csr->private);
1475 if (i & ~0x3)
Stefan Richter7fb9add2007-03-11 22:49:05 +01001476 return -EINVAL;
Ben Collins1934b8b2005-07-09 20:01:23 -04001477 csr->max_rom = mr_map[i];
1478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
1480 csr->cache_head->layout_head = csr->root_kv;
1481 csr->cache_head->layout_tail = csr->root_kv;
1482
1483 csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
1484 csr->bus_info_len;
1485
1486 csr->root_kv->valid = 0;
1487 csr->root_kv->next = csr->root_kv;
1488 csr->root_kv->prev = csr->root_kv;
Stefan Richterc1a37f22007-03-14 00:20:53 +01001489 ret = csr1212_read_keyval(csr, csr->root_kv);
Jody McIntyre5303a982005-11-22 12:17:11 -05001490 if (ret != CSR1212_SUCCESS)
1491 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
1493 /* Scan through the Root directory finding all extended ROM regions
1494 * and make cache regions for them */
1495 for (dentry = csr->root_kv->value.directory.dentries_head;
1496 dentry; dentry = dentry->next) {
Jody McIntyrea96074e2005-11-22 12:17:14 -05001497 if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
1498 !dentry->kv->valid) {
Stefan Richterc1a37f22007-03-14 00:20:53 +01001499 ret = csr1212_read_keyval(csr, dentry->kv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 if (ret != CSR1212_SUCCESS)
1501 return ret;
1502 }
1503 }
1504
1505 return CSR1212_SUCCESS;
1506}