Commit | Line | Data |
---|---|---|
6e74b38a GL |
1 | /* |
2 | * PS3 repository routines. | |
3 | * | |
4 | * Copyright (C) 2006 Sony Computer Entertainment Inc. | |
5 | * Copyright 2006 Sony Corp. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; version 2 of the License. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
6e74b38a GL |
21 | #include <asm/lv1call.h> |
22 | ||
2a08ea69 GL |
23 | #include "platform.h" |
24 | ||
6e74b38a GL |
25 | enum ps3_vendor_id { |
26 | PS3_VENDOR_ID_NONE = 0, | |
27 | PS3_VENDOR_ID_SONY = 0x8000000000000000UL, | |
28 | }; | |
29 | ||
30 | enum ps3_lpar_id { | |
31 | PS3_LPAR_ID_CURRENT = 0, | |
32 | PS3_LPAR_ID_PME = 1, | |
33 | }; | |
34 | ||
35 | #define dump_field(_a, _b) _dump_field(_a, _b, __func__, __LINE__) | |
720c9133 | 36 | static void _dump_field(const char *hdr, u64 n, const char *func, int line) |
6e74b38a GL |
37 | { |
38 | #if defined(DEBUG) | |
39 | char s[16]; | |
40 | const char *const in = (const char *)&n; | |
41 | unsigned int i; | |
42 | ||
43 | for (i = 0; i < 8; i++) | |
44 | s[i] = (in[i] <= 126 && in[i] >= 32) ? in[i] : '.'; | |
45 | s[i] = 0; | |
46 | ||
4bf94ae3 | 47 | pr_devel("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s); |
6e74b38a GL |
48 | #endif |
49 | } | |
50 | ||
51 | #define dump_node_name(_a, _b, _c, _d, _e) \ | |
52 | _dump_node_name(_a, _b, _c, _d, _e, __func__, __LINE__) | |
720c9133 GU |
53 | static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, |
54 | u64 n4, const char *func, int line) | |
6e74b38a | 55 | { |
4bf94ae3 | 56 | pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id); |
6e74b38a GL |
57 | _dump_field("n1: ", n1, func, line); |
58 | _dump_field("n2: ", n2, func, line); | |
59 | _dump_field("n3: ", n3, func, line); | |
60 | _dump_field("n4: ", n4, func, line); | |
61 | } | |
62 | ||
63 | #define dump_node(_a, _b, _c, _d, _e, _f, _g) \ | |
64 | _dump_node(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) | |
65 | static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, | |
720c9133 | 66 | u64 v1, u64 v2, const char *func, int line) |
6e74b38a | 67 | { |
4bf94ae3 | 68 | pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id); |
6e74b38a GL |
69 | _dump_field("n1: ", n1, func, line); |
70 | _dump_field("n2: ", n2, func, line); | |
71 | _dump_field("n3: ", n3, func, line); | |
72 | _dump_field("n4: ", n4, func, line); | |
4bf94ae3 GL |
73 | pr_devel("%s:%d: v1: %016llx\n", func, line, v1); |
74 | pr_devel("%s:%d: v2: %016llx\n", func, line, v2); | |
6e74b38a GL |
75 | } |
76 | ||
77 | /** | |
78 | * make_first_field - Make the first field of a repository node name. | |
79 | * @text: Text portion of the field. | |
80 | * @index: Numeric index portion of the field. Use zero for 'don't care'. | |
81 | * | |
82 | * This routine sets the vendor id to zero (non-vendor specific). | |
83 | * Returns field value. | |
84 | */ | |
85 | ||
86 | static u64 make_first_field(const char *text, u64 index) | |
87 | { | |
88 | u64 n; | |
89 | ||
90 | strncpy((char *)&n, text, 8); | |
91 | return PS3_VENDOR_ID_NONE + (n >> 32) + index; | |
92 | } | |
93 | ||
94 | /** | |
95 | * make_field - Make subsequent fields of a repository node name. | |
96 | * @text: Text portion of the field. Use "" for 'don't care'. | |
97 | * @index: Numeric index portion of the field. Use zero for 'don't care'. | |
98 | * | |
99 | * Returns field value. | |
100 | */ | |
101 | ||
102 | static u64 make_field(const char *text, u64 index) | |
103 | { | |
104 | u64 n; | |
105 | ||
106 | strncpy((char *)&n, text, 8); | |
107 | return n + index; | |
108 | } | |
109 | ||
110 | /** | |
111 | * read_node - Read a repository node from raw fields. | |
112 | * @n1: First field of node name. | |
113 | * @n2: Second field of node name. Use zero for 'don't care'. | |
114 | * @n3: Third field of node name. Use zero for 'don't care'. | |
115 | * @n4: Fourth field of node name. Use zero for 'don't care'. | |
116 | * @v1: First repository value (high word). | |
117 | * @v2: Second repository value (low word). Optional parameter, use zero | |
118 | * for 'don't care'. | |
119 | */ | |
120 | ||
121 | static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, | |
122 | u64 *_v1, u64 *_v2) | |
123 | { | |
124 | int result; | |
125 | u64 v1; | |
126 | u64 v2; | |
127 | ||
128 | if (lpar_id == PS3_LPAR_ID_CURRENT) { | |
129 | u64 id; | |
130 | lv1_get_logical_partition_id(&id); | |
131 | lpar_id = id; | |
132 | } | |
133 | ||
7f8cd352 | 134 | result = lv1_read_repository_node(lpar_id, n1, n2, n3, n4, &v1, |
6e74b38a GL |
135 | &v2); |
136 | ||
137 | if (result) { | |
4bf94ae3 | 138 | pr_warn("%s:%d: lv1_read_repository_node failed: %s\n", |
6e74b38a GL |
139 | __func__, __LINE__, ps3_result(result)); |
140 | dump_node_name(lpar_id, n1, n2, n3, n4); | |
a3323d1a | 141 | return -ENOENT; |
6e74b38a GL |
142 | } |
143 | ||
144 | dump_node(lpar_id, n1, n2, n3, n4, v1, v2); | |
145 | ||
146 | if (_v1) | |
147 | *_v1 = v1; | |
148 | if (_v2) | |
149 | *_v2 = v2; | |
150 | ||
151 | if (v1 && !_v1) | |
4bf94ae3 | 152 | pr_devel("%s:%d: warning: discarding non-zero v1: %016llx\n", |
6e74b38a GL |
153 | __func__, __LINE__, v1); |
154 | if (v2 && !_v2) | |
4bf94ae3 | 155 | pr_devel("%s:%d: warning: discarding non-zero v2: %016llx\n", |
6e74b38a GL |
156 | __func__, __LINE__, v2); |
157 | ||
a3323d1a | 158 | return 0; |
6e74b38a GL |
159 | } |
160 | ||
161 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, | |
162 | u64 *value) | |
163 | { | |
164 | return read_node(PS3_LPAR_ID_PME, | |
165 | make_first_field("bus", bus_index), | |
166 | make_field(bus_str, 0), | |
167 | 0, 0, | |
720c9133 | 168 | value, NULL); |
6e74b38a GL |
169 | } |
170 | ||
034e0ab5 | 171 | int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id) |
6e74b38a GL |
172 | { |
173 | int result; | |
6e74b38a GL |
174 | |
175 | result = read_node(PS3_LPAR_ID_PME, | |
176 | make_first_field("bus", bus_index), | |
177 | make_field("id", 0), | |
178 | 0, 0, | |
034e0ab5 | 179 | bus_id, NULL); |
6e74b38a GL |
180 | return result; |
181 | } | |
182 | ||
183 | int ps3_repository_read_bus_type(unsigned int bus_index, | |
184 | enum ps3_bus_type *bus_type) | |
185 | { | |
186 | int result; | |
5233e26e | 187 | u64 v1 = 0; |
6e74b38a GL |
188 | |
189 | result = read_node(PS3_LPAR_ID_PME, | |
190 | make_first_field("bus", bus_index), | |
191 | make_field("type", 0), | |
192 | 0, 0, | |
720c9133 | 193 | &v1, NULL); |
6e74b38a GL |
194 | *bus_type = v1; |
195 | return result; | |
196 | } | |
197 | ||
198 | int ps3_repository_read_bus_num_dev(unsigned int bus_index, | |
199 | unsigned int *num_dev) | |
200 | { | |
201 | int result; | |
5233e26e | 202 | u64 v1 = 0; |
6e74b38a GL |
203 | |
204 | result = read_node(PS3_LPAR_ID_PME, | |
205 | make_first_field("bus", bus_index), | |
206 | make_field("num_dev", 0), | |
207 | 0, 0, | |
720c9133 | 208 | &v1, NULL); |
6e74b38a GL |
209 | *num_dev = v1; |
210 | return result; | |
211 | } | |
212 | ||
213 | int ps3_repository_read_dev_str(unsigned int bus_index, | |
214 | unsigned int dev_index, const char *dev_str, u64 *value) | |
215 | { | |
216 | return read_node(PS3_LPAR_ID_PME, | |
217 | make_first_field("bus", bus_index), | |
218 | make_field("dev", dev_index), | |
219 | make_field(dev_str, 0), | |
220 | 0, | |
720c9133 | 221 | value, NULL); |
6e74b38a GL |
222 | } |
223 | ||
224 | int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, | |
034e0ab5 | 225 | u64 *dev_id) |
6e74b38a GL |
226 | { |
227 | int result; | |
6e74b38a GL |
228 | |
229 | result = read_node(PS3_LPAR_ID_PME, | |
230 | make_first_field("bus", bus_index), | |
231 | make_field("dev", dev_index), | |
232 | make_field("id", 0), | |
233 | 0, | |
720c9133 | 234 | dev_id, NULL); |
6e74b38a GL |
235 | return result; |
236 | } | |
237 | ||
238 | int ps3_repository_read_dev_type(unsigned int bus_index, | |
239 | unsigned int dev_index, enum ps3_dev_type *dev_type) | |
240 | { | |
241 | int result; | |
5233e26e | 242 | u64 v1 = 0; |
6e74b38a GL |
243 | |
244 | result = read_node(PS3_LPAR_ID_PME, | |
245 | make_first_field("bus", bus_index), | |
246 | make_field("dev", dev_index), | |
247 | make_field("type", 0), | |
248 | 0, | |
720c9133 | 249 | &v1, NULL); |
6e74b38a GL |
250 | *dev_type = v1; |
251 | return result; | |
252 | } | |
253 | ||
254 | int ps3_repository_read_dev_intr(unsigned int bus_index, | |
255 | unsigned int dev_index, unsigned int intr_index, | |
720c9133 | 256 | enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id) |
6e74b38a GL |
257 | { |
258 | int result; | |
5233e26e GL |
259 | u64 v1 = 0; |
260 | u64 v2 = 0; | |
6e74b38a GL |
261 | |
262 | result = read_node(PS3_LPAR_ID_PME, | |
263 | make_first_field("bus", bus_index), | |
264 | make_field("dev", dev_index), | |
265 | make_field("intr", intr_index), | |
266 | 0, | |
267 | &v1, &v2); | |
268 | *intr_type = v1; | |
269 | *interrupt_id = v2; | |
270 | return result; | |
271 | } | |
272 | ||
273 | int ps3_repository_read_dev_reg_type(unsigned int bus_index, | |
eebb81c1 GL |
274 | unsigned int dev_index, unsigned int reg_index, |
275 | enum ps3_reg_type *reg_type) | |
6e74b38a GL |
276 | { |
277 | int result; | |
5233e26e | 278 | u64 v1 = 0; |
6e74b38a GL |
279 | |
280 | result = read_node(PS3_LPAR_ID_PME, | |
281 | make_first_field("bus", bus_index), | |
282 | make_field("dev", dev_index), | |
283 | make_field("reg", reg_index), | |
284 | make_field("type", 0), | |
720c9133 | 285 | &v1, NULL); |
6e74b38a GL |
286 | *reg_type = v1; |
287 | return result; | |
288 | } | |
289 | ||
290 | int ps3_repository_read_dev_reg_addr(unsigned int bus_index, | |
291 | unsigned int dev_index, unsigned int reg_index, u64 *bus_addr, u64 *len) | |
292 | { | |
293 | return read_node(PS3_LPAR_ID_PME, | |
294 | make_first_field("bus", bus_index), | |
295 | make_field("dev", dev_index), | |
296 | make_field("reg", reg_index), | |
297 | make_field("data", 0), | |
298 | bus_addr, len); | |
299 | } | |
300 | ||
301 | int ps3_repository_read_dev_reg(unsigned int bus_index, | |
eebb81c1 GL |
302 | unsigned int dev_index, unsigned int reg_index, |
303 | enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len) | |
6e74b38a GL |
304 | { |
305 | int result = ps3_repository_read_dev_reg_type(bus_index, dev_index, | |
306 | reg_index, reg_type); | |
307 | return result ? result | |
308 | : ps3_repository_read_dev_reg_addr(bus_index, dev_index, | |
309 | reg_index, bus_addr, len); | |
310 | } | |
311 | ||
6e74b38a | 312 | |
6e74b38a | 313 | |
a3323d1a GL |
314 | int ps3_repository_find_device(struct ps3_repository_device *repo) |
315 | { | |
316 | int result; | |
317 | struct ps3_repository_device tmp = *repo; | |
318 | unsigned int num_dev; | |
6e74b38a | 319 | |
a3323d1a GL |
320 | BUG_ON(repo->bus_index > 10); |
321 | BUG_ON(repo->dev_index > 10); | |
6e74b38a | 322 | |
a3323d1a | 323 | result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); |
6e74b38a | 324 | |
a3323d1a | 325 | if (result) { |
4bf94ae3 | 326 | pr_devel("%s:%d read_bus_num_dev failed\n", __func__, __LINE__); |
a3323d1a | 327 | return result; |
6e74b38a GL |
328 | } |
329 | ||
4bf94ae3 | 330 | pr_devel("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n", |
a3323d1a GL |
331 | __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, |
332 | num_dev); | |
6e74b38a | 333 | |
a3323d1a | 334 | if (tmp.dev_index >= num_dev) { |
4bf94ae3 | 335 | pr_devel("%s:%d: no device found\n", __func__, __LINE__); |
a3323d1a | 336 | return -ENODEV; |
6e74b38a GL |
337 | } |
338 | ||
a3323d1a GL |
339 | result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index, |
340 | &tmp.dev_type); | |
6c7be7d3 | 341 | |
6c7be7d3 | 342 | if (result) { |
4bf94ae3 | 343 | pr_devel("%s:%d read_dev_type failed\n", __func__, __LINE__); |
a3323d1a | 344 | return result; |
6c7be7d3 GU |
345 | } |
346 | ||
a3323d1a GL |
347 | result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, |
348 | &tmp.dev_id); | |
6c7be7d3 | 349 | |
a3323d1a | 350 | if (result) { |
4bf94ae3 | 351 | pr_devel("%s:%d ps3_repository_read_dev_id failed\n", __func__, |
a3323d1a GL |
352 | __LINE__); |
353 | return result; | |
6c7be7d3 GU |
354 | } |
355 | ||
4bf94ae3 | 356 | pr_devel("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n", |
a3323d1a | 357 | __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); |
6e74b38a | 358 | |
a3323d1a GL |
359 | *repo = tmp; |
360 | return 0; | |
6e74b38a GL |
361 | } |
362 | ||
e06bcf3c GU |
363 | int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, |
364 | u64 bus_id, u64 dev_id) | |
365 | { | |
366 | int result = -ENODEV; | |
367 | struct ps3_repository_device tmp; | |
368 | unsigned int num_dev; | |
369 | ||
4bf94ae3 | 370 | pr_devel(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__, |
e06bcf3c GU |
371 | bus_id, dev_id); |
372 | ||
373 | for (tmp.bus_index = 0; tmp.bus_index < 10; tmp.bus_index++) { | |
374 | result = ps3_repository_read_bus_id(tmp.bus_index, | |
375 | &tmp.bus_id); | |
376 | if (result) { | |
4bf94ae3 | 377 | pr_devel("%s:%u read_bus_id(%u) failed\n", __func__, |
e06bcf3c GU |
378 | __LINE__, tmp.bus_index); |
379 | return result; | |
380 | } | |
381 | ||
382 | if (tmp.bus_id == bus_id) | |
383 | goto found_bus; | |
384 | ||
4bf94ae3 | 385 | pr_devel("%s:%u: skip, bus_id %llu\n", __func__, __LINE__, |
e06bcf3c GU |
386 | tmp.bus_id); |
387 | } | |
4bf94ae3 | 388 | pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__); |
e06bcf3c GU |
389 | return result; |
390 | ||
391 | found_bus: | |
392 | result = ps3_repository_read_bus_type(tmp.bus_index, &tmp.bus_type); | |
393 | if (result) { | |
4bf94ae3 | 394 | pr_devel("%s:%u read_bus_type(%u) failed\n", __func__, |
e06bcf3c GU |
395 | __LINE__, tmp.bus_index); |
396 | return result; | |
397 | } | |
398 | ||
399 | result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); | |
400 | if (result) { | |
4bf94ae3 | 401 | pr_devel("%s:%u read_bus_num_dev failed\n", __func__, |
e06bcf3c GU |
402 | __LINE__); |
403 | return result; | |
404 | } | |
405 | ||
406 | for (tmp.dev_index = 0; tmp.dev_index < num_dev; tmp.dev_index++) { | |
407 | result = ps3_repository_read_dev_id(tmp.bus_index, | |
408 | tmp.dev_index, | |
409 | &tmp.dev_id); | |
410 | if (result) { | |
4bf94ae3 | 411 | pr_devel("%s:%u read_dev_id(%u:%u) failed\n", __func__, |
e06bcf3c GU |
412 | __LINE__, tmp.bus_index, tmp.dev_index); |
413 | return result; | |
414 | } | |
415 | ||
416 | if (tmp.dev_id == dev_id) | |
417 | goto found_dev; | |
418 | ||
4bf94ae3 | 419 | pr_devel("%s:%u: skip, dev_id %llu\n", __func__, __LINE__, |
e06bcf3c GU |
420 | tmp.dev_id); |
421 | } | |
4bf94ae3 | 422 | pr_devel(" <- %s:%u: dev not found\n", __func__, __LINE__); |
e06bcf3c GU |
423 | return result; |
424 | ||
425 | found_dev: | |
426 | result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index, | |
427 | &tmp.dev_type); | |
428 | if (result) { | |
4bf94ae3 | 429 | pr_devel("%s:%u read_dev_type failed\n", __func__, __LINE__); |
e06bcf3c GU |
430 | return result; |
431 | } | |
432 | ||
4bf94ae3 | 433 | pr_devel(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n", |
e06bcf3c GU |
434 | __func__, __LINE__, tmp.bus_type, tmp.dev_type, tmp.bus_index, |
435 | tmp.dev_index, tmp.bus_id, tmp.dev_id); | |
436 | *repo = tmp; | |
437 | return 0; | |
438 | } | |
439 | ||
cad5cef6 | 440 | int ps3_repository_find_devices(enum ps3_bus_type bus_type, |
a3323d1a | 441 | int (*callback)(const struct ps3_repository_device *repo)) |
6e74b38a GL |
442 | { |
443 | int result = 0; | |
a3323d1a | 444 | struct ps3_repository_device repo; |
6e74b38a | 445 | |
4bf94ae3 | 446 | pr_devel(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); |
6e74b38a | 447 | |
ad7d8193 GU |
448 | repo.bus_type = bus_type; |
449 | result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index); | |
450 | if (result) { | |
4bf94ae3 | 451 | pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__); |
ad7d8193 GU |
452 | return result; |
453 | } | |
6e74b38a | 454 | |
ad7d8193 GU |
455 | result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id); |
456 | if (result) { | |
4bf94ae3 | 457 | pr_devel("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__, |
ad7d8193 GU |
458 | repo.bus_index); |
459 | return result; | |
460 | } | |
6e74b38a | 461 | |
ad7d8193 GU |
462 | for (repo.dev_index = 0; ; repo.dev_index++) { |
463 | result = ps3_repository_find_device(&repo); | |
464 | if (result == -ENODEV) { | |
465 | result = 0; | |
466 | break; | |
467 | } else if (result) | |
6e74b38a | 468 | break; |
6e74b38a | 469 | |
ad7d8193 | 470 | result = callback(&repo); |
6e74b38a | 471 | if (result) { |
4bf94ae3 | 472 | pr_devel("%s:%d: abort at callback\n", __func__, |
ad7d8193 GU |
473 | __LINE__); |
474 | break; | |
6e74b38a | 475 | } |
6e74b38a GL |
476 | } |
477 | ||
4bf94ae3 | 478 | pr_devel(" <- %s:%d\n", __func__, __LINE__); |
6e74b38a GL |
479 | return result; |
480 | } | |
481 | ||
a3323d1a GL |
482 | int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, |
483 | unsigned int *bus_index) | |
6e74b38a | 484 | { |
a3323d1a GL |
485 | unsigned int i; |
486 | enum ps3_bus_type type; | |
487 | int error; | |
6e74b38a | 488 | |
a3323d1a GL |
489 | for (i = from; i < 10; i++) { |
490 | error = ps3_repository_read_bus_type(i, &type); | |
491 | if (error) { | |
4bf94ae3 | 492 | pr_devel("%s:%d read_bus_type failed\n", |
6e74b38a | 493 | __func__, __LINE__); |
a3323d1a GL |
494 | *bus_index = UINT_MAX; |
495 | return error; | |
496 | } | |
497 | if (type == bus_type) { | |
498 | *bus_index = i; | |
499 | return 0; | |
6e74b38a | 500 | } |
6e74b38a | 501 | } |
a3323d1a GL |
502 | *bus_index = UINT_MAX; |
503 | return -ENODEV; | |
6e74b38a GL |
504 | } |
505 | ||
a3323d1a | 506 | int ps3_repository_find_interrupt(const struct ps3_repository_device *repo, |
6e74b38a GL |
507 | enum ps3_interrupt_type intr_type, unsigned int *interrupt_id) |
508 | { | |
509 | int result = 0; | |
510 | unsigned int res_index; | |
511 | ||
4bf94ae3 | 512 | pr_devel("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type); |
6e74b38a GL |
513 | |
514 | *interrupt_id = UINT_MAX; | |
515 | ||
516 | for (res_index = 0; res_index < 10; res_index++) { | |
517 | enum ps3_interrupt_type t; | |
518 | unsigned int id; | |
519 | ||
a3323d1a GL |
520 | result = ps3_repository_read_dev_intr(repo->bus_index, |
521 | repo->dev_index, res_index, &t, &id); | |
6e74b38a GL |
522 | |
523 | if (result) { | |
4bf94ae3 | 524 | pr_devel("%s:%d read_dev_intr failed\n", |
6e74b38a GL |
525 | __func__, __LINE__); |
526 | return result; | |
527 | } | |
528 | ||
529 | if (t == intr_type) { | |
530 | *interrupt_id = id; | |
531 | break; | |
532 | } | |
533 | } | |
534 | ||
eebb81c1 GL |
535 | if (res_index == 10) |
536 | return -ENODEV; | |
6e74b38a | 537 | |
4bf94ae3 | 538 | pr_devel("%s:%d: found intr_type %u at res_index %u\n", |
6e74b38a GL |
539 | __func__, __LINE__, intr_type, res_index); |
540 | ||
541 | return result; | |
542 | } | |
543 | ||
a3323d1a | 544 | int ps3_repository_find_reg(const struct ps3_repository_device *repo, |
eebb81c1 | 545 | enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len) |
6e74b38a GL |
546 | { |
547 | int result = 0; | |
548 | unsigned int res_index; | |
549 | ||
4bf94ae3 | 550 | pr_devel("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type); |
6e74b38a GL |
551 | |
552 | *bus_addr = *len = 0; | |
553 | ||
554 | for (res_index = 0; res_index < 10; res_index++) { | |
eebb81c1 | 555 | enum ps3_reg_type t; |
6e74b38a GL |
556 | u64 a; |
557 | u64 l; | |
558 | ||
a3323d1a GL |
559 | result = ps3_repository_read_dev_reg(repo->bus_index, |
560 | repo->dev_index, res_index, &t, &a, &l); | |
6e74b38a GL |
561 | |
562 | if (result) { | |
4bf94ae3 | 563 | pr_devel("%s:%d read_dev_reg failed\n", |
6e74b38a GL |
564 | __func__, __LINE__); |
565 | return result; | |
566 | } | |
567 | ||
568 | if (t == reg_type) { | |
569 | *bus_addr = a; | |
570 | *len = l; | |
571 | break; | |
572 | } | |
573 | } | |
574 | ||
eebb81c1 GL |
575 | if (res_index == 10) |
576 | return -ENODEV; | |
6e74b38a | 577 | |
4bf94ae3 | 578 | pr_devel("%s:%d: found reg_type %u at res_index %u\n", |
6e74b38a GL |
579 | __func__, __LINE__, reg_type, res_index); |
580 | ||
581 | return result; | |
582 | } | |
583 | ||
6c7be7d3 GU |
584 | int ps3_repository_read_stor_dev_port(unsigned int bus_index, |
585 | unsigned int dev_index, u64 *port) | |
586 | { | |
587 | return read_node(PS3_LPAR_ID_PME, | |
588 | make_first_field("bus", bus_index), | |
589 | make_field("dev", dev_index), | |
590 | make_field("port", 0), | |
720c9133 | 591 | 0, port, NULL); |
6c7be7d3 GU |
592 | } |
593 | ||
594 | int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, | |
595 | unsigned int dev_index, u64 *blk_size) | |
596 | { | |
597 | return read_node(PS3_LPAR_ID_PME, | |
598 | make_first_field("bus", bus_index), | |
599 | make_field("dev", dev_index), | |
600 | make_field("blk_size", 0), | |
720c9133 | 601 | 0, blk_size, NULL); |
6c7be7d3 GU |
602 | } |
603 | ||
604 | int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, | |
605 | unsigned int dev_index, u64 *num_blocks) | |
606 | { | |
607 | return read_node(PS3_LPAR_ID_PME, | |
608 | make_first_field("bus", bus_index), | |
609 | make_field("dev", dev_index), | |
610 | make_field("n_blocks", 0), | |
720c9133 | 611 | 0, num_blocks, NULL); |
6c7be7d3 GU |
612 | } |
613 | ||
614 | int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, | |
615 | unsigned int dev_index, unsigned int *num_regions) | |
616 | { | |
617 | int result; | |
5233e26e | 618 | u64 v1 = 0; |
6c7be7d3 GU |
619 | |
620 | result = read_node(PS3_LPAR_ID_PME, | |
621 | make_first_field("bus", bus_index), | |
622 | make_field("dev", dev_index), | |
623 | make_field("n_regs", 0), | |
720c9133 | 624 | 0, &v1, NULL); |
6c7be7d3 GU |
625 | *num_regions = v1; |
626 | return result; | |
627 | } | |
628 | ||
629 | int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, | |
630 | unsigned int dev_index, unsigned int region_index, | |
631 | unsigned int *region_id) | |
632 | { | |
633 | int result; | |
5233e26e | 634 | u64 v1 = 0; |
6c7be7d3 GU |
635 | |
636 | result = read_node(PS3_LPAR_ID_PME, | |
637 | make_first_field("bus", bus_index), | |
638 | make_field("dev", dev_index), | |
639 | make_field("region", region_index), | |
640 | make_field("id", 0), | |
720c9133 | 641 | &v1, NULL); |
6c7be7d3 GU |
642 | *region_id = v1; |
643 | return result; | |
644 | } | |
645 | ||
646 | int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, | |
647 | unsigned int dev_index, unsigned int region_index, u64 *region_size) | |
648 | { | |
649 | return read_node(PS3_LPAR_ID_PME, | |
650 | make_first_field("bus", bus_index), | |
651 | make_field("dev", dev_index), | |
652 | make_field("region", region_index), | |
653 | make_field("size", 0), | |
720c9133 | 654 | region_size, NULL); |
6c7be7d3 GU |
655 | } |
656 | ||
657 | int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, | |
658 | unsigned int dev_index, unsigned int region_index, u64 *region_start) | |
659 | { | |
660 | return read_node(PS3_LPAR_ID_PME, | |
661 | make_first_field("bus", bus_index), | |
662 | make_field("dev", dev_index), | |
663 | make_field("region", region_index), | |
664 | make_field("start", 0), | |
720c9133 | 665 | region_start, NULL); |
6c7be7d3 GU |
666 | } |
667 | ||
668 | int ps3_repository_read_stor_dev_info(unsigned int bus_index, | |
669 | unsigned int dev_index, u64 *port, u64 *blk_size, | |
670 | u64 *num_blocks, unsigned int *num_regions) | |
671 | { | |
672 | int result; | |
673 | ||
674 | result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port); | |
675 | if (result) | |
676 | return result; | |
677 | ||
678 | result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index, | |
679 | blk_size); | |
680 | if (result) | |
681 | return result; | |
682 | ||
683 | result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index, | |
684 | num_blocks); | |
685 | if (result) | |
686 | return result; | |
687 | ||
688 | result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index, | |
689 | num_regions); | |
690 | return result; | |
691 | } | |
692 | ||
693 | int ps3_repository_read_stor_dev_region(unsigned int bus_index, | |
694 | unsigned int dev_index, unsigned int region_index, | |
695 | unsigned int *region_id, u64 *region_start, u64 *region_size) | |
696 | { | |
697 | int result; | |
698 | ||
699 | result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index, | |
700 | region_index, region_id); | |
701 | if (result) | |
702 | return result; | |
703 | ||
704 | result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index, | |
705 | region_index, region_start); | |
706 | if (result) | |
707 | return result; | |
708 | ||
709 | result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index, | |
710 | region_index, region_size); | |
711 | return result; | |
712 | } | |
713 | ||
c2b16e1c TY |
714 | /** |
715 | * ps3_repository_read_num_pu - Number of logical PU processors for this lpar. | |
716 | */ | |
717 | ||
718 | int ps3_repository_read_num_pu(u64 *num_pu) | |
719 | { | |
720 | *num_pu = 0; | |
721 | return read_node(PS3_LPAR_ID_CURRENT, | |
722 | make_first_field("bi", 0), | |
723 | make_field("pun", 0), | |
724 | 0, 0, | |
725 | num_pu, NULL); | |
726 | } | |
727 | ||
728 | /** | |
729 | * ps3_repository_read_pu_id - Read the logical PU id. | |
730 | * @pu_index: Zero based index. | |
731 | * @pu_id: The logical PU id. | |
732 | */ | |
733 | ||
734 | int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id) | |
735 | { | |
736 | return read_node(PS3_LPAR_ID_CURRENT, | |
737 | make_first_field("bi", 0), | |
738 | make_field("pu", pu_index), | |
739 | 0, 0, | |
740 | pu_id, NULL); | |
741 | } | |
742 | ||
6e74b38a GL |
743 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) |
744 | { | |
745 | return read_node(PS3_LPAR_ID_CURRENT, | |
746 | make_first_field("bi", 0), | |
747 | make_field("pu", 0), | |
748 | ppe_id, | |
749 | make_field("rm_size", 0), | |
720c9133 | 750 | rm_size, NULL); |
6e74b38a GL |
751 | } |
752 | ||
753 | int ps3_repository_read_region_total(u64 *region_total) | |
754 | { | |
755 | return read_node(PS3_LPAR_ID_CURRENT, | |
756 | make_first_field("bi", 0), | |
757 | make_field("rgntotal", 0), | |
758 | 0, 0, | |
720c9133 | 759 | region_total, NULL); |
6e74b38a GL |
760 | } |
761 | ||
762 | /** | |
763 | * ps3_repository_read_mm_info - Read mm info for single pu system. | |
764 | * @rm_base: Real mode memory base address. | |
765 | * @rm_size: Real mode memory size. | |
766 | * @region_total: Maximum memory region size. | |
767 | */ | |
768 | ||
769 | int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total) | |
770 | { | |
771 | int result; | |
772 | u64 ppe_id; | |
773 | ||
774 | lv1_get_logical_ppe_id(&ppe_id); | |
775 | *rm_base = 0; | |
776 | result = ps3_repository_read_rm_size(ppe_id, rm_size); | |
777 | return result ? result | |
778 | : ps3_repository_read_region_total(region_total); | |
779 | } | |
780 | ||
6750edbd AH |
781 | /** |
782 | * ps3_repository_read_highmem_region_count - Read the number of highmem regions | |
783 | * | |
784 | * Bootloaders must arrange the repository nodes such that regions are indexed | |
785 | * with a region_index from 0 to region_count-1. | |
786 | */ | |
787 | ||
788 | int ps3_repository_read_highmem_region_count(unsigned int *region_count) | |
789 | { | |
790 | int result; | |
791 | u64 v1 = 0; | |
792 | ||
793 | result = read_node(PS3_LPAR_ID_CURRENT, | |
794 | make_first_field("highmem", 0), | |
795 | make_field("region", 0), | |
796 | make_field("count", 0), | |
797 | 0, | |
798 | &v1, NULL); | |
799 | *region_count = v1; | |
800 | return result; | |
801 | } | |
802 | ||
803 | ||
804 | int ps3_repository_read_highmem_base(unsigned int region_index, | |
805 | u64 *highmem_base) | |
806 | { | |
807 | return read_node(PS3_LPAR_ID_CURRENT, | |
808 | make_first_field("highmem", 0), | |
809 | make_field("region", region_index), | |
810 | make_field("base", 0), | |
811 | 0, | |
812 | highmem_base, NULL); | |
813 | } | |
814 | ||
815 | int ps3_repository_read_highmem_size(unsigned int region_index, | |
816 | u64 *highmem_size) | |
817 | { | |
818 | return read_node(PS3_LPAR_ID_CURRENT, | |
819 | make_first_field("highmem", 0), | |
820 | make_field("region", region_index), | |
821 | make_field("size", 0), | |
822 | 0, | |
823 | highmem_size, NULL); | |
824 | } | |
825 | ||
826 | /** | |
827 | * ps3_repository_read_highmem_info - Read high memory region info | |
828 | * @region_index: Region index, {0,..,region_count-1}. | |
829 | * @highmem_base: High memory base address. | |
830 | * @highmem_size: High memory size. | |
831 | * | |
832 | * Bootloaders that preallocate highmem regions must place the | |
833 | * region info into the repository at these well known nodes. | |
834 | */ | |
835 | ||
836 | int ps3_repository_read_highmem_info(unsigned int region_index, | |
837 | u64 *highmem_base, u64 *highmem_size) | |
838 | { | |
839 | int result; | |
840 | ||
841 | *highmem_base = 0; | |
842 | result = ps3_repository_read_highmem_base(region_index, highmem_base); | |
843 | return result ? result | |
844 | : ps3_repository_read_highmem_size(region_index, highmem_size); | |
845 | } | |
846 | ||
6e74b38a GL |
847 | /** |
848 | * ps3_repository_read_num_spu_reserved - Number of physical spus reserved. | |
849 | * @num_spu: Number of physical spus. | |
850 | */ | |
851 | ||
852 | int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved) | |
853 | { | |
854 | int result; | |
5233e26e | 855 | u64 v1 = 0; |
6e74b38a GL |
856 | |
857 | result = read_node(PS3_LPAR_ID_CURRENT, | |
858 | make_first_field("bi", 0), | |
859 | make_field("spun", 0), | |
860 | 0, 0, | |
720c9133 | 861 | &v1, NULL); |
6e74b38a GL |
862 | *num_spu_reserved = v1; |
863 | return result; | |
864 | } | |
865 | ||
866 | /** | |
867 | * ps3_repository_read_num_spu_resource_id - Number of spu resource reservations. | |
868 | * @num_resource_id: Number of spu resource ids. | |
869 | */ | |
870 | ||
871 | int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id) | |
872 | { | |
873 | int result; | |
5233e26e | 874 | u64 v1 = 0; |
6e74b38a GL |
875 | |
876 | result = read_node(PS3_LPAR_ID_CURRENT, | |
877 | make_first_field("bi", 0), | |
878 | make_field("spursvn", 0), | |
879 | 0, 0, | |
720c9133 | 880 | &v1, NULL); |
6e74b38a GL |
881 | *num_resource_id = v1; |
882 | return result; | |
883 | } | |
884 | ||
885 | /** | |
886 | * ps3_repository_read_spu_resource_id - spu resource reservation id value. | |
887 | * @res_index: Resource reservation index. | |
888 | * @resource_type: Resource reservation type. | |
889 | * @resource_id: Resource reservation id. | |
890 | */ | |
891 | ||
892 | int ps3_repository_read_spu_resource_id(unsigned int res_index, | |
720c9133 | 893 | enum ps3_spu_resource_type *resource_type, unsigned int *resource_id) |
6e74b38a GL |
894 | { |
895 | int result; | |
5233e26e GL |
896 | u64 v1 = 0; |
897 | u64 v2 = 0; | |
6e74b38a GL |
898 | |
899 | result = read_node(PS3_LPAR_ID_CURRENT, | |
900 | make_first_field("bi", 0), | |
901 | make_field("spursv", 0), | |
902 | res_index, | |
903 | 0, | |
904 | &v1, &v2); | |
905 | *resource_type = v1; | |
906 | *resource_id = v2; | |
907 | return result; | |
908 | } | |
909 | ||
720c9133 | 910 | static int ps3_repository_read_boot_dat_address(u64 *address) |
6e74b38a GL |
911 | { |
912 | return read_node(PS3_LPAR_ID_CURRENT, | |
913 | make_first_field("bi", 0), | |
914 | make_field("boot_dat", 0), | |
915 | make_field("address", 0), | |
916 | 0, | |
720c9133 | 917 | address, NULL); |
6e74b38a GL |
918 | } |
919 | ||
920 | int ps3_repository_read_boot_dat_size(unsigned int *size) | |
921 | { | |
922 | int result; | |
5233e26e | 923 | u64 v1 = 0; |
6e74b38a GL |
924 | |
925 | result = read_node(PS3_LPAR_ID_CURRENT, | |
926 | make_first_field("bi", 0), | |
927 | make_field("boot_dat", 0), | |
928 | make_field("size", 0), | |
929 | 0, | |
720c9133 | 930 | &v1, NULL); |
6e74b38a GL |
931 | *size = v1; |
932 | return result; | |
933 | } | |
934 | ||
a3323d1a GL |
935 | int ps3_repository_read_vuart_av_port(unsigned int *port) |
936 | { | |
937 | int result; | |
5233e26e | 938 | u64 v1 = 0; |
a3323d1a GL |
939 | |
940 | result = read_node(PS3_LPAR_ID_CURRENT, | |
941 | make_first_field("bi", 0), | |
942 | make_field("vir_uart", 0), | |
943 | make_field("port", 0), | |
944 | make_field("avset", 0), | |
720c9133 | 945 | &v1, NULL); |
a3323d1a GL |
946 | *port = v1; |
947 | return result; | |
948 | } | |
949 | ||
950 | int ps3_repository_read_vuart_sysmgr_port(unsigned int *port) | |
951 | { | |
952 | int result; | |
5233e26e | 953 | u64 v1 = 0; |
a3323d1a GL |
954 | |
955 | result = read_node(PS3_LPAR_ID_CURRENT, | |
956 | make_first_field("bi", 0), | |
957 | make_field("vir_uart", 0), | |
958 | make_field("port", 0), | |
959 | make_field("sysmgr", 0), | |
720c9133 | 960 | &v1, NULL); |
a3323d1a GL |
961 | *port = v1; |
962 | return result; | |
963 | } | |
964 | ||
6e74b38a GL |
965 | /** |
966 | * ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area. | |
967 | * address: lpar address of cell_ext_os_area | |
968 | * @size: size of cell_ext_os_area | |
969 | */ | |
970 | ||
971 | int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size) | |
972 | { | |
973 | int result; | |
974 | ||
975 | *size = 0; | |
976 | result = ps3_repository_read_boot_dat_address(lpar_addr); | |
977 | return result ? result | |
978 | : ps3_repository_read_boot_dat_size(size); | |
979 | } | |
980 | ||
c2b16e1c TY |
981 | /** |
982 | * ps3_repository_read_num_be - Number of physical BE processors in the system. | |
983 | */ | |
984 | ||
6e74b38a GL |
985 | int ps3_repository_read_num_be(unsigned int *num_be) |
986 | { | |
987 | int result; | |
5233e26e | 988 | u64 v1 = 0; |
6e74b38a GL |
989 | |
990 | result = read_node(PS3_LPAR_ID_PME, | |
991 | make_first_field("ben", 0), | |
992 | 0, | |
993 | 0, | |
994 | 0, | |
720c9133 | 995 | &v1, NULL); |
6e74b38a GL |
996 | *num_be = v1; |
997 | return result; | |
998 | } | |
999 | ||
c2b16e1c TY |
1000 | /** |
1001 | * ps3_repository_read_be_node_id - Read the physical BE processor node id. | |
1002 | * @be_index: Zero based index. | |
1003 | * @node_id: The BE processor node id. | |
1004 | */ | |
1005 | ||
6e74b38a GL |
1006 | int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id) |
1007 | { | |
1008 | return read_node(PS3_LPAR_ID_PME, | |
1009 | make_first_field("be", be_index), | |
1010 | 0, | |
1011 | 0, | |
1012 | 0, | |
720c9133 | 1013 | node_id, NULL); |
6e74b38a GL |
1014 | } |
1015 | ||
c2b16e1c TY |
1016 | /** |
1017 | * ps3_repository_read_be_id - Read the physical BE processor id. | |
1018 | * @node_id: The BE processor node id. | |
1019 | * @be_id: The BE processor id. | |
1020 | */ | |
1021 | ||
1022 | int ps3_repository_read_be_id(u64 node_id, u64 *be_id) | |
1023 | { | |
1024 | return read_node(PS3_LPAR_ID_PME, | |
1025 | make_first_field("be", 0), | |
1026 | node_id, | |
1027 | 0, | |
1028 | 0, | |
1029 | be_id, NULL); | |
1030 | } | |
1031 | ||
6e74b38a GL |
1032 | int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq) |
1033 | { | |
1034 | return read_node(PS3_LPAR_ID_PME, | |
1035 | make_first_field("be", 0), | |
1036 | node_id, | |
1037 | make_field("clock", 0), | |
1038 | 0, | |
720c9133 | 1039 | tb_freq, NULL); |
6e74b38a GL |
1040 | } |
1041 | ||
1042 | int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) | |
1043 | { | |
1044 | int result; | |
1045 | u64 node_id; | |
1046 | ||
1047 | *tb_freq = 0; | |
c2b16e1c | 1048 | result = ps3_repository_read_be_node_id(be_index, &node_id); |
6e74b38a GL |
1049 | return result ? result |
1050 | : ps3_repository_read_tb_freq(node_id, tb_freq); | |
1051 | } | |
a3323d1a | 1052 | |
c2b16e1c TY |
1053 | int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar, |
1054 | u64 *rights) | |
1055 | { | |
1056 | int result; | |
1057 | u64 node_id; | |
1058 | ||
1059 | *lpar = 0; | |
1060 | *rights = 0; | |
1061 | result = ps3_repository_read_be_node_id(be_index, &node_id); | |
1062 | return result ? result | |
1063 | : read_node(PS3_LPAR_ID_PME, | |
1064 | make_first_field("be", 0), | |
1065 | node_id, | |
1066 | make_field("lpm", 0), | |
1067 | make_field("priv", 0), | |
1068 | lpar, rights); | |
1069 | } | |
1070 | ||
07c044c8 GL |
1071 | #if defined(CONFIG_PS3_REPOSITORY_WRITE) |
1072 | ||
1073 | static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2) | |
1074 | { | |
1075 | int result; | |
1076 | ||
1077 | dump_node(0, n1, n2, n3, n4, v1, v2); | |
1078 | ||
1079 | result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2); | |
1080 | ||
1081 | if (result) { | |
1082 | pr_devel("%s:%d: lv1_create_repository_node failed: %s\n", | |
1083 | __func__, __LINE__, ps3_result(result)); | |
1084 | return -ENOENT; | |
1085 | } | |
1086 | ||
1087 | return 0; | |
1088 | } | |
1089 | ||
1090 | static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4) | |
1091 | { | |
1092 | int result; | |
1093 | ||
1094 | dump_node(0, n1, n2, n3, n4, 0, 0); | |
1095 | ||
1096 | result = lv1_delete_repository_node(n1, n2, n3, n4); | |
1097 | ||
1098 | if (result) { | |
1099 | pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n", | |
1100 | __func__, __LINE__, ps3_result(result)); | |
1101 | return -ENOENT; | |
1102 | } | |
1103 | ||
1104 | return 0; | |
1105 | } | |
1106 | ||
1107 | static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2) | |
1108 | { | |
1109 | int result; | |
1110 | ||
1111 | result = create_node(n1, n2, n3, n4, v1, v2); | |
1112 | ||
1113 | if (!result) | |
1114 | return 0; | |
1115 | ||
1116 | result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2); | |
1117 | ||
1118 | if (result) { | |
1119 | pr_devel("%s:%d: lv1_write_repository_node failed: %s\n", | |
1120 | __func__, __LINE__, ps3_result(result)); | |
1121 | return -ENOENT; | |
1122 | } | |
1123 | ||
1124 | return 0; | |
1125 | } | |
1126 | ||
79f2a81b GL |
1127 | int ps3_repository_write_highmem_region_count(unsigned int region_count) |
1128 | { | |
1129 | int result; | |
1130 | u64 v1 = (u64)region_count; | |
1131 | ||
1132 | result = write_node( | |
1133 | make_first_field("highmem", 0), | |
1134 | make_field("region", 0), | |
1135 | make_field("count", 0), | |
1136 | 0, | |
1137 | v1, 0); | |
1138 | return result; | |
1139 | } | |
1140 | ||
1141 | int ps3_repository_write_highmem_base(unsigned int region_index, | |
1142 | u64 highmem_base) | |
1143 | { | |
1144 | return write_node( | |
1145 | make_first_field("highmem", 0), | |
1146 | make_field("region", region_index), | |
1147 | make_field("base", 0), | |
1148 | 0, | |
1149 | highmem_base, 0); | |
1150 | } | |
1151 | ||
1152 | int ps3_repository_write_highmem_size(unsigned int region_index, | |
1153 | u64 highmem_size) | |
1154 | { | |
1155 | return write_node( | |
1156 | make_first_field("highmem", 0), | |
1157 | make_field("region", region_index), | |
1158 | make_field("size", 0), | |
1159 | 0, | |
1160 | highmem_size, 0); | |
1161 | } | |
1162 | ||
1163 | int ps3_repository_write_highmem_info(unsigned int region_index, | |
1164 | u64 highmem_base, u64 highmem_size) | |
1165 | { | |
1166 | int result; | |
1167 | ||
1168 | result = ps3_repository_write_highmem_base(region_index, highmem_base); | |
1169 | return result ? result | |
1170 | : ps3_repository_write_highmem_size(region_index, highmem_size); | |
1171 | } | |
1172 | ||
1173 | static int ps3_repository_delete_highmem_base(unsigned int region_index) | |
1174 | { | |
1175 | return delete_node( | |
1176 | make_first_field("highmem", 0), | |
1177 | make_field("region", region_index), | |
1178 | make_field("base", 0), | |
1179 | 0); | |
1180 | } | |
1181 | ||
1182 | static int ps3_repository_delete_highmem_size(unsigned int region_index) | |
1183 | { | |
1184 | return delete_node( | |
1185 | make_first_field("highmem", 0), | |
1186 | make_field("region", region_index), | |
1187 | make_field("size", 0), | |
1188 | 0); | |
1189 | } | |
1190 | ||
1191 | int ps3_repository_delete_highmem_info(unsigned int region_index) | |
1192 | { | |
1193 | int result; | |
1194 | ||
1195 | result = ps3_repository_delete_highmem_base(region_index); | |
1196 | result += ps3_repository_delete_highmem_size(region_index); | |
1197 | ||
1198 | return result ? -1 : 0; | |
1199 | } | |
1200 | ||
07c044c8 GL |
1201 | #endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */ |
1202 | ||
a3323d1a GL |
1203 | #if defined(DEBUG) |
1204 | ||
1205 | int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) | |
1206 | { | |
1207 | int result = 0; | |
1208 | unsigned int res_index; | |
1209 | ||
4bf94ae3 | 1210 | pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, |
a3323d1a GL |
1211 | repo->bus_index, repo->dev_index); |
1212 | ||
1213 | for (res_index = 0; res_index < 10; res_index++) { | |
1214 | enum ps3_interrupt_type intr_type; | |
1215 | unsigned int interrupt_id; | |
1216 | ||
1217 | result = ps3_repository_read_dev_intr(repo->bus_index, | |
1218 | repo->dev_index, res_index, &intr_type, &interrupt_id); | |
1219 | ||
1220 | if (result) { | |
1221 | if (result != LV1_NO_ENTRY) | |
4bf94ae3 | 1222 | pr_devel("%s:%d ps3_repository_read_dev_intr" |
a3323d1a GL |
1223 | " (%u:%u) failed\n", __func__, __LINE__, |
1224 | repo->bus_index, repo->dev_index); | |
1225 | break; | |
1226 | } | |
1227 | ||
4bf94ae3 | 1228 | pr_devel("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n", |
a3323d1a GL |
1229 | __func__, __LINE__, repo->bus_index, repo->dev_index, |
1230 | intr_type, interrupt_id); | |
1231 | } | |
1232 | ||
1233 | for (res_index = 0; res_index < 10; res_index++) { | |
1234 | enum ps3_reg_type reg_type; | |
1235 | u64 bus_addr; | |
1236 | u64 len; | |
1237 | ||
1238 | result = ps3_repository_read_dev_reg(repo->bus_index, | |
1239 | repo->dev_index, res_index, ®_type, &bus_addr, &len); | |
1240 | ||
1241 | if (result) { | |
1242 | if (result != LV1_NO_ENTRY) | |
4bf94ae3 | 1243 | pr_devel("%s:%d ps3_repository_read_dev_reg" |
a3323d1a GL |
1244 | " (%u:%u) failed\n", __func__, __LINE__, |
1245 | repo->bus_index, repo->dev_index); | |
1246 | break; | |
1247 | } | |
1248 | ||
4bf94ae3 | 1249 | pr_devel("%s:%d (%u:%u) reg_type %u, bus_addr %llxh, len %llxh\n", |
a3323d1a GL |
1250 | __func__, __LINE__, repo->bus_index, repo->dev_index, |
1251 | reg_type, bus_addr, len); | |
1252 | } | |
1253 | ||
4bf94ae3 | 1254 | pr_devel(" <- %s:%d\n", __func__, __LINE__); |
a3323d1a GL |
1255 | return result; |
1256 | } | |
1257 | ||
1258 | static int dump_stor_dev_info(struct ps3_repository_device *repo) | |
1259 | { | |
1260 | int result = 0; | |
1261 | unsigned int num_regions, region_index; | |
1262 | u64 port, blk_size, num_blocks; | |
1263 | ||
4bf94ae3 | 1264 | pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, |
a3323d1a GL |
1265 | repo->bus_index, repo->dev_index); |
1266 | ||
1267 | result = ps3_repository_read_stor_dev_info(repo->bus_index, | |
1268 | repo->dev_index, &port, &blk_size, &num_blocks, &num_regions); | |
1269 | if (result) { | |
4bf94ae3 | 1270 | pr_devel("%s:%d ps3_repository_read_stor_dev_info" |
a3323d1a GL |
1271 | " (%u:%u) failed\n", __func__, __LINE__, |
1272 | repo->bus_index, repo->dev_index); | |
1273 | goto out; | |
1274 | } | |
1275 | ||
4bf94ae3 GL |
1276 | pr_devel("%s:%d (%u:%u): port %llu, blk_size %llu, num_blocks " |
1277 | "%llu, num_regions %u\n", | |
1278 | __func__, __LINE__, repo->bus_index, repo->dev_index, | |
1279 | port, blk_size, num_blocks, num_regions); | |
a3323d1a GL |
1280 | |
1281 | for (region_index = 0; region_index < num_regions; region_index++) { | |
1282 | unsigned int region_id; | |
1283 | u64 region_start, region_size; | |
1284 | ||
1285 | result = ps3_repository_read_stor_dev_region(repo->bus_index, | |
1286 | repo->dev_index, region_index, ®ion_id, | |
1287 | ®ion_start, ®ion_size); | |
1288 | if (result) { | |
4bf94ae3 | 1289 | pr_devel("%s:%d ps3_repository_read_stor_dev_region" |
a3323d1a GL |
1290 | " (%u:%u) failed\n", __func__, __LINE__, |
1291 | repo->bus_index, repo->dev_index); | |
1292 | break; | |
1293 | } | |
1294 | ||
4bf94ae3 | 1295 | pr_devel("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", |
a3323d1a | 1296 | __func__, __LINE__, repo->bus_index, repo->dev_index, |
4bf94ae3 GL |
1297 | region_id, (unsigned long)region_start, |
1298 | (unsigned long)region_size); | |
a3323d1a GL |
1299 | } |
1300 | ||
1301 | out: | |
4bf94ae3 | 1302 | pr_devel(" <- %s:%d\n", __func__, __LINE__); |
a3323d1a GL |
1303 | return result; |
1304 | } | |
1305 | ||
1306 | static int dump_device_info(struct ps3_repository_device *repo, | |
1307 | unsigned int num_dev) | |
1308 | { | |
1309 | int result = 0; | |
1310 | ||
4bf94ae3 | 1311 | pr_devel(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index); |
a3323d1a GL |
1312 | |
1313 | for (repo->dev_index = 0; repo->dev_index < num_dev; | |
1314 | repo->dev_index++) { | |
1315 | ||
1316 | result = ps3_repository_read_dev_type(repo->bus_index, | |
1317 | repo->dev_index, &repo->dev_type); | |
1318 | ||
1319 | if (result) { | |
4bf94ae3 | 1320 | pr_devel("%s:%d ps3_repository_read_dev_type" |
a3323d1a GL |
1321 | " (%u:%u) failed\n", __func__, __LINE__, |
1322 | repo->bus_index, repo->dev_index); | |
1323 | break; | |
1324 | } | |
1325 | ||
1326 | result = ps3_repository_read_dev_id(repo->bus_index, | |
1327 | repo->dev_index, &repo->dev_id); | |
1328 | ||
1329 | if (result) { | |
4bf94ae3 | 1330 | pr_devel("%s:%d ps3_repository_read_dev_id" |
a3323d1a GL |
1331 | " (%u:%u) failed\n", __func__, __LINE__, |
1332 | repo->bus_index, repo->dev_index); | |
1333 | continue; | |
1334 | } | |
1335 | ||
4bf94ae3 | 1336 | pr_devel("%s:%d (%u:%u): dev_type %u, dev_id %lu\n", __func__, |
a3323d1a | 1337 | __LINE__, repo->bus_index, repo->dev_index, |
4bf94ae3 | 1338 | repo->dev_type, (unsigned long)repo->dev_id); |
a3323d1a GL |
1339 | |
1340 | ps3_repository_dump_resource_info(repo); | |
1341 | ||
1342 | if (repo->bus_type == PS3_BUS_TYPE_STORAGE) | |
1343 | dump_stor_dev_info(repo); | |
1344 | } | |
1345 | ||
4bf94ae3 | 1346 | pr_devel(" <- %s:%d\n", __func__, __LINE__); |
a3323d1a GL |
1347 | return result; |
1348 | } | |
1349 | ||
1350 | int ps3_repository_dump_bus_info(void) | |
1351 | { | |
1352 | int result = 0; | |
1353 | struct ps3_repository_device repo; | |
1354 | ||
4bf94ae3 | 1355 | pr_devel(" -> %s:%d\n", __func__, __LINE__); |
a3323d1a GL |
1356 | |
1357 | memset(&repo, 0, sizeof(repo)); | |
1358 | ||
1359 | for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { | |
1360 | unsigned int num_dev; | |
1361 | ||
1362 | result = ps3_repository_read_bus_type(repo.bus_index, | |
1363 | &repo.bus_type); | |
1364 | ||
1365 | if (result) { | |
4bf94ae3 | 1366 | pr_devel("%s:%d read_bus_type(%u) failed\n", |
a3323d1a GL |
1367 | __func__, __LINE__, repo.bus_index); |
1368 | break; | |
1369 | } | |
1370 | ||
1371 | result = ps3_repository_read_bus_id(repo.bus_index, | |
1372 | &repo.bus_id); | |
1373 | ||
1374 | if (result) { | |
4bf94ae3 | 1375 | pr_devel("%s:%d read_bus_id(%u) failed\n", |
a3323d1a GL |
1376 | __func__, __LINE__, repo.bus_index); |
1377 | continue; | |
1378 | } | |
1379 | ||
1380 | if (repo.bus_index != repo.bus_id) | |
4bf94ae3 | 1381 | pr_devel("%s:%d bus_index != bus_id\n", |
a3323d1a GL |
1382 | __func__, __LINE__); |
1383 | ||
1384 | result = ps3_repository_read_bus_num_dev(repo.bus_index, | |
1385 | &num_dev); | |
1386 | ||
1387 | if (result) { | |
4bf94ae3 | 1388 | pr_devel("%s:%d read_bus_num_dev(%u) failed\n", |
a3323d1a GL |
1389 | __func__, __LINE__, repo.bus_index); |
1390 | continue; | |
1391 | } | |
1392 | ||
4bf94ae3 | 1393 | pr_devel("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n", |
a3323d1a | 1394 | __func__, __LINE__, repo.bus_index, repo.bus_type, |
4bf94ae3 | 1395 | (unsigned long)repo.bus_id, num_dev); |
a3323d1a GL |
1396 | |
1397 | dump_device_info(&repo, num_dev); | |
1398 | } | |
1399 | ||
4bf94ae3 | 1400 | pr_devel(" <- %s:%d\n", __func__, __LINE__); |
a3323d1a GL |
1401 | return result; |
1402 | } | |
1403 | ||
1404 | #endif /* defined(DEBUG) */ |