2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-26 14:14:01 +08:00
linux-next/arch/powerpc/platforms/ps3/repository.c
Andre Heider 6750edbd8d powerpc/ps3: Add highmem repository read routines
Add repository helper routines to read highmem region info.

Bootloaders that preallocate highmem regions must place the
region info into the repository at these well known nodes.
These routines allow second stage kernles to read the region
info from those nodes.

Signed-off-by: Andre Heider <a.heider@gmail.com>
CC: Nathan Whitehorn <nwhitehorn@freebsd.org>
Signed-off-by: Geoff Levand <geoff@infradead.org>
2012-04-24 15:34:17 -07:00

1405 lines
33 KiB
C

/*
* PS3 repository routines.
*
* Copyright (C) 2006 Sony Computer Entertainment Inc.
* Copyright 2006 Sony Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/lv1call.h>
#include "platform.h"
enum ps3_vendor_id {
PS3_VENDOR_ID_NONE = 0,
PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
};
enum ps3_lpar_id {
PS3_LPAR_ID_CURRENT = 0,
PS3_LPAR_ID_PME = 1,
};
#define dump_field(_a, _b) _dump_field(_a, _b, __func__, __LINE__)
static void _dump_field(const char *hdr, u64 n, const char *func, int line)
{
#if defined(DEBUG)
char s[16];
const char *const in = (const char *)&n;
unsigned int i;
for (i = 0; i < 8; i++)
s[i] = (in[i] <= 126 && in[i] >= 32) ? in[i] : '.';
s[i] = 0;
pr_devel("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s);
#endif
}
#define dump_node_name(_a, _b, _c, _d, _e) \
_dump_node_name(_a, _b, _c, _d, _e, __func__, __LINE__)
static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3,
u64 n4, const char *func, int line)
{
pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id);
_dump_field("n1: ", n1, func, line);
_dump_field("n2: ", n2, func, line);
_dump_field("n3: ", n3, func, line);
_dump_field("n4: ", n4, func, line);
}
#define dump_node(_a, _b, _c, _d, _e, _f, _g) \
_dump_node(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
u64 v1, u64 v2, const char *func, int line)
{
pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id);
_dump_field("n1: ", n1, func, line);
_dump_field("n2: ", n2, func, line);
_dump_field("n3: ", n3, func, line);
_dump_field("n4: ", n4, func, line);
pr_devel("%s:%d: v1: %016llx\n", func, line, v1);
pr_devel("%s:%d: v2: %016llx\n", func, line, v2);
}
/**
* make_first_field - Make the first field of a repository node name.
* @text: Text portion of the field.
* @index: Numeric index portion of the field. Use zero for 'don't care'.
*
* This routine sets the vendor id to zero (non-vendor specific).
* Returns field value.
*/
static u64 make_first_field(const char *text, u64 index)
{
u64 n;
strncpy((char *)&n, text, 8);
return PS3_VENDOR_ID_NONE + (n >> 32) + index;
}
/**
* make_field - Make subsequent fields of a repository node name.
* @text: Text portion of the field. Use "" for 'don't care'.
* @index: Numeric index portion of the field. Use zero for 'don't care'.
*
* Returns field value.
*/
static u64 make_field(const char *text, u64 index)
{
u64 n;
strncpy((char *)&n, text, 8);
return n + index;
}
/**
* read_node - Read a repository node from raw fields.
* @n1: First field of node name.
* @n2: Second field of node name. Use zero for 'don't care'.
* @n3: Third field of node name. Use zero for 'don't care'.
* @n4: Fourth field of node name. Use zero for 'don't care'.
* @v1: First repository value (high word).
* @v2: Second repository value (low word). Optional parameter, use zero
* for 'don't care'.
*/
static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
u64 *_v1, u64 *_v2)
{
int result;
u64 v1;
u64 v2;
if (lpar_id == PS3_LPAR_ID_CURRENT) {
u64 id;
lv1_get_logical_partition_id(&id);
lpar_id = id;
}
result = lv1_read_repository_node(lpar_id, n1, n2, n3, n4, &v1,
&v2);
if (result) {
pr_warn("%s:%d: lv1_read_repository_node failed: %s\n",
__func__, __LINE__, ps3_result(result));
dump_node_name(lpar_id, n1, n2, n3, n4);
return -ENOENT;
}
dump_node(lpar_id, n1, n2, n3, n4, v1, v2);
if (_v1)
*_v1 = v1;
if (_v2)
*_v2 = v2;
if (v1 && !_v1)
pr_devel("%s:%d: warning: discarding non-zero v1: %016llx\n",
__func__, __LINE__, v1);
if (v2 && !_v2)
pr_devel("%s:%d: warning: discarding non-zero v2: %016llx\n",
__func__, __LINE__, v2);
return 0;
}
int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
u64 *value)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field(bus_str, 0),
0, 0,
value, NULL);
}
int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id)
{
int result;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("id", 0),
0, 0,
bus_id, NULL);
return result;
}
int ps3_repository_read_bus_type(unsigned int bus_index,
enum ps3_bus_type *bus_type)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("type", 0),
0, 0,
&v1, NULL);
*bus_type = v1;
return result;
}
int ps3_repository_read_bus_num_dev(unsigned int bus_index,
unsigned int *num_dev)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("num_dev", 0),
0, 0,
&v1, NULL);
*num_dev = v1;
return result;
}
int ps3_repository_read_dev_str(unsigned int bus_index,
unsigned int dev_index, const char *dev_str, u64 *value)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field(dev_str, 0),
0,
value, NULL);
}
int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
u64 *dev_id)
{
int result;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("id", 0),
0,
dev_id, NULL);
return result;
}
int ps3_repository_read_dev_type(unsigned int bus_index,
unsigned int dev_index, enum ps3_dev_type *dev_type)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("type", 0),
0,
&v1, NULL);
*dev_type = v1;
return result;
}
int ps3_repository_read_dev_intr(unsigned int bus_index,
unsigned int dev_index, unsigned int intr_index,
enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id)
{
int result;
u64 v1 = 0;
u64 v2 = 0;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("intr", intr_index),
0,
&v1, &v2);
*intr_type = v1;
*interrupt_id = v2;
return result;
}
int ps3_repository_read_dev_reg_type(unsigned int bus_index,
unsigned int dev_index, unsigned int reg_index,
enum ps3_reg_type *reg_type)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("reg", reg_index),
make_field("type", 0),
&v1, NULL);
*reg_type = v1;
return result;
}
int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
unsigned int dev_index, unsigned int reg_index, u64 *bus_addr, u64 *len)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("reg", reg_index),
make_field("data", 0),
bus_addr, len);
}
int ps3_repository_read_dev_reg(unsigned int bus_index,
unsigned int dev_index, unsigned int reg_index,
enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len)
{
int result = ps3_repository_read_dev_reg_type(bus_index, dev_index,
reg_index, reg_type);
return result ? result
: ps3_repository_read_dev_reg_addr(bus_index, dev_index,
reg_index, bus_addr, len);
}
int ps3_repository_find_device(struct ps3_repository_device *repo)
{
int result;
struct ps3_repository_device tmp = *repo;
unsigned int num_dev;
BUG_ON(repo->bus_index > 10);
BUG_ON(repo->dev_index > 10);
result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);
if (result) {
pr_devel("%s:%d read_bus_num_dev failed\n", __func__, __LINE__);
return result;
}
pr_devel("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n",
__func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id,
num_dev);
if (tmp.dev_index >= num_dev) {
pr_devel("%s:%d: no device found\n", __func__, __LINE__);
return -ENODEV;
}
result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index,
&tmp.dev_type);
if (result) {
pr_devel("%s:%d read_dev_type failed\n", __func__, __LINE__);
return result;
}
result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index,
&tmp.dev_id);
if (result) {
pr_devel("%s:%d ps3_repository_read_dev_id failed\n", __func__,
__LINE__);
return result;
}
pr_devel("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n",
__func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id);
*repo = tmp;
return 0;
}
int ps3_repository_find_device_by_id(struct ps3_repository_device *repo,
u64 bus_id, u64 dev_id)
{
int result = -ENODEV;
struct ps3_repository_device tmp;
unsigned int num_dev;
pr_devel(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__,
bus_id, dev_id);
for (tmp.bus_index = 0; tmp.bus_index < 10; tmp.bus_index++) {
result = ps3_repository_read_bus_id(tmp.bus_index,
&tmp.bus_id);
if (result) {
pr_devel("%s:%u read_bus_id(%u) failed\n", __func__,
__LINE__, tmp.bus_index);
return result;
}
if (tmp.bus_id == bus_id)
goto found_bus;
pr_devel("%s:%u: skip, bus_id %llu\n", __func__, __LINE__,
tmp.bus_id);
}
pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__);
return result;
found_bus:
result = ps3_repository_read_bus_type(tmp.bus_index, &tmp.bus_type);
if (result) {
pr_devel("%s:%u read_bus_type(%u) failed\n", __func__,
__LINE__, tmp.bus_index);
return result;
}
result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);
if (result) {
pr_devel("%s:%u read_bus_num_dev failed\n", __func__,
__LINE__);
return result;
}
for (tmp.dev_index = 0; tmp.dev_index < num_dev; tmp.dev_index++) {
result = ps3_repository_read_dev_id(tmp.bus_index,
tmp.dev_index,
&tmp.dev_id);
if (result) {
pr_devel("%s:%u read_dev_id(%u:%u) failed\n", __func__,
__LINE__, tmp.bus_index, tmp.dev_index);
return result;
}
if (tmp.dev_id == dev_id)
goto found_dev;
pr_devel("%s:%u: skip, dev_id %llu\n", __func__, __LINE__,
tmp.dev_id);
}
pr_devel(" <- %s:%u: dev not found\n", __func__, __LINE__);
return result;
found_dev:
result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index,
&tmp.dev_type);
if (result) {
pr_devel("%s:%u read_dev_type failed\n", __func__, __LINE__);
return result;
}
pr_devel(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n",
__func__, __LINE__, tmp.bus_type, tmp.dev_type, tmp.bus_index,
tmp.dev_index, tmp.bus_id, tmp.dev_id);
*repo = tmp;
return 0;
}
int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type,
int (*callback)(const struct ps3_repository_device *repo))
{
int result = 0;
struct ps3_repository_device repo;
pr_devel(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type);
repo.bus_type = bus_type;
result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index);
if (result) {
pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__);
return result;
}
result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id);
if (result) {
pr_devel("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__,
repo.bus_index);
return result;
}
for (repo.dev_index = 0; ; repo.dev_index++) {
result = ps3_repository_find_device(&repo);
if (result == -ENODEV) {
result = 0;
break;
} else if (result)
break;
result = callback(&repo);
if (result) {
pr_devel("%s:%d: abort at callback\n", __func__,
__LINE__);
break;
}
}
pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from,
unsigned int *bus_index)
{
unsigned int i;
enum ps3_bus_type type;
int error;
for (i = from; i < 10; i++) {
error = ps3_repository_read_bus_type(i, &type);
if (error) {
pr_devel("%s:%d read_bus_type failed\n",
__func__, __LINE__);
*bus_index = UINT_MAX;
return error;
}
if (type == bus_type) {
*bus_index = i;
return 0;
}
}
*bus_index = UINT_MAX;
return -ENODEV;
}
int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,
enum ps3_interrupt_type intr_type, unsigned int *interrupt_id)
{
int result = 0;
unsigned int res_index;
pr_devel("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type);
*interrupt_id = UINT_MAX;
for (res_index = 0; res_index < 10; res_index++) {
enum ps3_interrupt_type t;
unsigned int id;
result = ps3_repository_read_dev_intr(repo->bus_index,
repo->dev_index, res_index, &t, &id);
if (result) {
pr_devel("%s:%d read_dev_intr failed\n",
__func__, __LINE__);
return result;
}
if (t == intr_type) {
*interrupt_id = id;
break;
}
}
if (res_index == 10)
return -ENODEV;
pr_devel("%s:%d: found intr_type %u at res_index %u\n",
__func__, __LINE__, intr_type, res_index);
return result;
}
int ps3_repository_find_reg(const struct ps3_repository_device *repo,
enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len)
{
int result = 0;
unsigned int res_index;
pr_devel("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type);
*bus_addr = *len = 0;
for (res_index = 0; res_index < 10; res_index++) {
enum ps3_reg_type t;
u64 a;
u64 l;
result = ps3_repository_read_dev_reg(repo->bus_index,
repo->dev_index, res_index, &t, &a, &l);
if (result) {
pr_devel("%s:%d read_dev_reg failed\n",
__func__, __LINE__);
return result;
}
if (t == reg_type) {
*bus_addr = a;
*len = l;
break;
}
}
if (res_index == 10)
return -ENODEV;
pr_devel("%s:%d: found reg_type %u at res_index %u\n",
__func__, __LINE__, reg_type, res_index);
return result;
}
int ps3_repository_read_stor_dev_port(unsigned int bus_index,
unsigned int dev_index, u64 *port)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("port", 0),
0, port, NULL);
}
int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
unsigned int dev_index, u64 *blk_size)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("blk_size", 0),
0, blk_size, NULL);
}
int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
unsigned int dev_index, u64 *num_blocks)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("n_blocks", 0),
0, num_blocks, NULL);
}
int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
unsigned int dev_index, unsigned int *num_regions)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("n_regs", 0),
0, &v1, NULL);
*num_regions = v1;
return result;
}
int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
unsigned int dev_index, unsigned int region_index,
unsigned int *region_id)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("region", region_index),
make_field("id", 0),
&v1, NULL);
*region_id = v1;
return result;
}
int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
unsigned int dev_index, unsigned int region_index, u64 *region_size)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("region", region_index),
make_field("size", 0),
region_size, NULL);
}
int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
unsigned int dev_index, unsigned int region_index, u64 *region_start)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("bus", bus_index),
make_field("dev", dev_index),
make_field("region", region_index),
make_field("start", 0),
region_start, NULL);
}
int ps3_repository_read_stor_dev_info(unsigned int bus_index,
unsigned int dev_index, u64 *port, u64 *blk_size,
u64 *num_blocks, unsigned int *num_regions)
{
int result;
result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port);
if (result)
return result;
result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index,
blk_size);
if (result)
return result;
result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index,
num_blocks);
if (result)
return result;
result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index,
num_regions);
return result;
}
int ps3_repository_read_stor_dev_region(unsigned int bus_index,
unsigned int dev_index, unsigned int region_index,
unsigned int *region_id, u64 *region_start, u64 *region_size)
{
int result;
result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index,
region_index, region_id);
if (result)
return result;
result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index,
region_index, region_start);
if (result)
return result;
result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index,
region_index, region_size);
return result;
}
/**
* ps3_repository_read_num_pu - Number of logical PU processors for this lpar.
*/
int ps3_repository_read_num_pu(u64 *num_pu)
{
*num_pu = 0;
return read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("pun", 0),
0, 0,
num_pu, NULL);
}
/**
* ps3_repository_read_pu_id - Read the logical PU id.
* @pu_index: Zero based index.
* @pu_id: The logical PU id.
*/
int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id)
{
return read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("pu", pu_index),
0, 0,
pu_id, NULL);
}
int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size)
{
return read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("pu", 0),
ppe_id,
make_field("rm_size", 0),
rm_size, NULL);
}
int ps3_repository_read_region_total(u64 *region_total)
{
return read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("rgntotal", 0),
0, 0,
region_total, NULL);
}
/**
* ps3_repository_read_mm_info - Read mm info for single pu system.
* @rm_base: Real mode memory base address.
* @rm_size: Real mode memory size.
* @region_total: Maximum memory region size.
*/
int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)
{
int result;
u64 ppe_id;
lv1_get_logical_ppe_id(&ppe_id);
*rm_base = 0;
result = ps3_repository_read_rm_size(ppe_id, rm_size);
return result ? result
: ps3_repository_read_region_total(region_total);
}
/**
* ps3_repository_read_highmem_region_count - Read the number of highmem regions
*
* Bootloaders must arrange the repository nodes such that regions are indexed
* with a region_index from 0 to region_count-1.
*/
int ps3_repository_read_highmem_region_count(unsigned int *region_count)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_CURRENT,
make_first_field("highmem", 0),
make_field("region", 0),
make_field("count", 0),
0,
&v1, NULL);
*region_count = v1;
return result;
}
int ps3_repository_read_highmem_base(unsigned int region_index,
u64 *highmem_base)
{
return read_node(PS3_LPAR_ID_CURRENT,
make_first_field("highmem", 0),
make_field("region", region_index),
make_field("base", 0),
0,
highmem_base, NULL);
}
int ps3_repository_read_highmem_size(unsigned int region_index,
u64 *highmem_size)
{
return read_node(PS3_LPAR_ID_CURRENT,
make_first_field("highmem", 0),
make_field("region", region_index),
make_field("size", 0),
0,
highmem_size, NULL);
}
/**
* ps3_repository_read_highmem_info - Read high memory region info
* @region_index: Region index, {0,..,region_count-1}.
* @highmem_base: High memory base address.
* @highmem_size: High memory size.
*
* Bootloaders that preallocate highmem regions must place the
* region info into the repository at these well known nodes.
*/
int ps3_repository_read_highmem_info(unsigned int region_index,
u64 *highmem_base, u64 *highmem_size)
{
int result;
*highmem_base = 0;
result = ps3_repository_read_highmem_base(region_index, highmem_base);
return result ? result
: ps3_repository_read_highmem_size(region_index, highmem_size);
}
/**
* ps3_repository_read_num_spu_reserved - Number of physical spus reserved.
* @num_spu: Number of physical spus.
*/
int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("spun", 0),
0, 0,
&v1, NULL);
*num_spu_reserved = v1;
return result;
}
/**
* ps3_repository_read_num_spu_resource_id - Number of spu resource reservations.
* @num_resource_id: Number of spu resource ids.
*/
int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("spursvn", 0),
0, 0,
&v1, NULL);
*num_resource_id = v1;
return result;
}
/**
* ps3_repository_read_spu_resource_id - spu resource reservation id value.
* @res_index: Resource reservation index.
* @resource_type: Resource reservation type.
* @resource_id: Resource reservation id.
*/
int ps3_repository_read_spu_resource_id(unsigned int res_index,
enum ps3_spu_resource_type *resource_type, unsigned int *resource_id)
{
int result;
u64 v1 = 0;
u64 v2 = 0;
result = read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("spursv", 0),
res_index,
0,
&v1, &v2);
*resource_type = v1;
*resource_id = v2;
return result;
}
static int ps3_repository_read_boot_dat_address(u64 *address)
{
return read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("boot_dat", 0),
make_field("address", 0),
0,
address, NULL);
}
int ps3_repository_read_boot_dat_size(unsigned int *size)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("boot_dat", 0),
make_field("size", 0),
0,
&v1, NULL);
*size = v1;
return result;
}
int ps3_repository_read_vuart_av_port(unsigned int *port)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("vir_uart", 0),
make_field("port", 0),
make_field("avset", 0),
&v1, NULL);
*port = v1;
return result;
}
int ps3_repository_read_vuart_sysmgr_port(unsigned int *port)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_CURRENT,
make_first_field("bi", 0),
make_field("vir_uart", 0),
make_field("port", 0),
make_field("sysmgr", 0),
&v1, NULL);
*port = v1;
return result;
}
/**
* ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area.
* address: lpar address of cell_ext_os_area
* @size: size of cell_ext_os_area
*/
int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size)
{
int result;
*size = 0;
result = ps3_repository_read_boot_dat_address(lpar_addr);
return result ? result
: ps3_repository_read_boot_dat_size(size);
}
/**
* ps3_repository_read_num_be - Number of physical BE processors in the system.
*/
int ps3_repository_read_num_be(unsigned int *num_be)
{
int result;
u64 v1 = 0;
result = read_node(PS3_LPAR_ID_PME,
make_first_field("ben", 0),
0,
0,
0,
&v1, NULL);
*num_be = v1;
return result;
}
/**
* ps3_repository_read_be_node_id - Read the physical BE processor node id.
* @be_index: Zero based index.
* @node_id: The BE processor node id.
*/
int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("be", be_index),
0,
0,
0,
node_id, NULL);
}
/**
* ps3_repository_read_be_id - Read the physical BE processor id.
* @node_id: The BE processor node id.
* @be_id: The BE processor id.
*/
int ps3_repository_read_be_id(u64 node_id, u64 *be_id)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("be", 0),
node_id,
0,
0,
be_id, NULL);
}
int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq)
{
return read_node(PS3_LPAR_ID_PME,
make_first_field("be", 0),
node_id,
make_field("clock", 0),
0,
tb_freq, NULL);
}
int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq)
{
int result;
u64 node_id;
*tb_freq = 0;
result = ps3_repository_read_be_node_id(be_index, &node_id);
return result ? result
: ps3_repository_read_tb_freq(node_id, tb_freq);
}
int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar,
u64 *rights)
{
int result;
u64 node_id;
*lpar = 0;
*rights = 0;
result = ps3_repository_read_be_node_id(be_index, &node_id);
return result ? result
: read_node(PS3_LPAR_ID_PME,
make_first_field("be", 0),
node_id,
make_field("lpm", 0),
make_field("priv", 0),
lpar, rights);
}
#if defined(CONFIG_PS3_REPOSITORY_WRITE)
static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
{
int result;
dump_node(0, n1, n2, n3, n4, v1, v2);
result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2);
if (result) {
pr_devel("%s:%d: lv1_create_repository_node failed: %s\n",
__func__, __LINE__, ps3_result(result));
return -ENOENT;
}
return 0;
}
static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4)
{
int result;
dump_node(0, n1, n2, n3, n4, 0, 0);
result = lv1_delete_repository_node(n1, n2, n3, n4);
if (result) {
pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n",
__func__, __LINE__, ps3_result(result));
return -ENOENT;
}
return 0;
}
static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
{
int result;
result = create_node(n1, n2, n3, n4, v1, v2);
if (!result)
return 0;
result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2);
if (result) {
pr_devel("%s:%d: lv1_write_repository_node failed: %s\n",
__func__, __LINE__, ps3_result(result));
return -ENOENT;
}
return 0;
}
int ps3_repository_write_highmem_region_count(unsigned int region_count)
{
int result;
u64 v1 = (u64)region_count;
result = write_node(
make_first_field("highmem", 0),
make_field("region", 0),
make_field("count", 0),
0,
v1, 0);
return result;
}
int ps3_repository_write_highmem_base(unsigned int region_index,
u64 highmem_base)
{
return write_node(
make_first_field("highmem", 0),
make_field("region", region_index),
make_field("base", 0),
0,
highmem_base, 0);
}
int ps3_repository_write_highmem_size(unsigned int region_index,
u64 highmem_size)
{
return write_node(
make_first_field("highmem", 0),
make_field("region", region_index),
make_field("size", 0),
0,
highmem_size, 0);
}
int ps3_repository_write_highmem_info(unsigned int region_index,
u64 highmem_base, u64 highmem_size)
{
int result;
result = ps3_repository_write_highmem_base(region_index, highmem_base);
return result ? result
: ps3_repository_write_highmem_size(region_index, highmem_size);
}
static int ps3_repository_delete_highmem_base(unsigned int region_index)
{
return delete_node(
make_first_field("highmem", 0),
make_field("region", region_index),
make_field("base", 0),
0);
}
static int ps3_repository_delete_highmem_size(unsigned int region_index)
{
return delete_node(
make_first_field("highmem", 0),
make_field("region", region_index),
make_field("size", 0),
0);
}
int ps3_repository_delete_highmem_info(unsigned int region_index)
{
int result;
result = ps3_repository_delete_highmem_base(region_index);
result += ps3_repository_delete_highmem_size(region_index);
return result ? -1 : 0;
}
#endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */
#if defined(DEBUG)
int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
{
int result = 0;
unsigned int res_index;
pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
for (res_index = 0; res_index < 10; res_index++) {
enum ps3_interrupt_type intr_type;
unsigned int interrupt_id;
result = ps3_repository_read_dev_intr(repo->bus_index,
repo->dev_index, res_index, &intr_type, &interrupt_id);
if (result) {
if (result != LV1_NO_ENTRY)
pr_devel("%s:%d ps3_repository_read_dev_intr"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
break;
}
pr_devel("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n",
__func__, __LINE__, repo->bus_index, repo->dev_index,
intr_type, interrupt_id);
}
for (res_index = 0; res_index < 10; res_index++) {
enum ps3_reg_type reg_type;
u64 bus_addr;
u64 len;
result = ps3_repository_read_dev_reg(repo->bus_index,
repo->dev_index, res_index, &reg_type, &bus_addr, &len);
if (result) {
if (result != LV1_NO_ENTRY)
pr_devel("%s:%d ps3_repository_read_dev_reg"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
break;
}
pr_devel("%s:%d (%u:%u) reg_type %u, bus_addr %llxh, len %llxh\n",
__func__, __LINE__, repo->bus_index, repo->dev_index,
reg_type, bus_addr, len);
}
pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
static int dump_stor_dev_info(struct ps3_repository_device *repo)
{
int result = 0;
unsigned int num_regions, region_index;
u64 port, blk_size, num_blocks;
pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
result = ps3_repository_read_stor_dev_info(repo->bus_index,
repo->dev_index, &port, &blk_size, &num_blocks, &num_regions);
if (result) {
pr_devel("%s:%d ps3_repository_read_stor_dev_info"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
goto out;
}
pr_devel("%s:%d (%u:%u): port %llu, blk_size %llu, num_blocks "
"%llu, num_regions %u\n",
__func__, __LINE__, repo->bus_index, repo->dev_index,
port, blk_size, num_blocks, num_regions);
for (region_index = 0; region_index < num_regions; region_index++) {
unsigned int region_id;
u64 region_start, region_size;
result = ps3_repository_read_stor_dev_region(repo->bus_index,
repo->dev_index, region_index, &region_id,
&region_start, &region_size);
if (result) {
pr_devel("%s:%d ps3_repository_read_stor_dev_region"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
break;
}
pr_devel("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
__func__, __LINE__, repo->bus_index, repo->dev_index,
region_id, (unsigned long)region_start,
(unsigned long)region_size);
}
out:
pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
static int dump_device_info(struct ps3_repository_device *repo,
unsigned int num_dev)
{
int result = 0;
pr_devel(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index);
for (repo->dev_index = 0; repo->dev_index < num_dev;
repo->dev_index++) {
result = ps3_repository_read_dev_type(repo->bus_index,
repo->dev_index, &repo->dev_type);
if (result) {
pr_devel("%s:%d ps3_repository_read_dev_type"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
break;
}
result = ps3_repository_read_dev_id(repo->bus_index,
repo->dev_index, &repo->dev_id);
if (result) {
pr_devel("%s:%d ps3_repository_read_dev_id"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
continue;
}
pr_devel("%s:%d (%u:%u): dev_type %u, dev_id %lu\n", __func__,
__LINE__, repo->bus_index, repo->dev_index,
repo->dev_type, (unsigned long)repo->dev_id);
ps3_repository_dump_resource_info(repo);
if (repo->bus_type == PS3_BUS_TYPE_STORAGE)
dump_stor_dev_info(repo);
}
pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
int ps3_repository_dump_bus_info(void)
{
int result = 0;
struct ps3_repository_device repo;
pr_devel(" -> %s:%d\n", __func__, __LINE__);
memset(&repo, 0, sizeof(repo));
for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) {
unsigned int num_dev;
result = ps3_repository_read_bus_type(repo.bus_index,
&repo.bus_type);
if (result) {
pr_devel("%s:%d read_bus_type(%u) failed\n",
__func__, __LINE__, repo.bus_index);
break;
}
result = ps3_repository_read_bus_id(repo.bus_index,
&repo.bus_id);
if (result) {
pr_devel("%s:%d read_bus_id(%u) failed\n",
__func__, __LINE__, repo.bus_index);
continue;
}
if (repo.bus_index != repo.bus_id)
pr_devel("%s:%d bus_index != bus_id\n",
__func__, __LINE__);
result = ps3_repository_read_bus_num_dev(repo.bus_index,
&num_dev);
if (result) {
pr_devel("%s:%d read_bus_num_dev(%u) failed\n",
__func__, __LINE__, repo.bus_index);
continue;
}
pr_devel("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n",
__func__, __LINE__, repo.bus_index, repo.bus_type,
(unsigned long)repo.bus_id, num_dev);
dump_device_info(&repo, num_dev);
}
pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
#endif /* defined(DEBUG) */