cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

repository.c (32901B)


      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;
     77
     78	strncpy((char *)&n, text, 8);
     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) */