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