📄 repository.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_debug("%s:%d: %s%016lx : %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_debug("%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_debug("%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_debug("%s:%d: v1: %016lx\n", func, line, v1); pr_debug("%s:%d: v2: %016lx\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_get_repository_node_value(lpar_id, n1, n2, n3, n4, &v1, &v2); if (result) { pr_debug("%s:%d: lv1_get_repository_node_value 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_debug("%s:%d: warning: discarding non-zero v1: %016lx\n", __func__, __LINE__, v1); if (v2 && !_v2) pr_debug("%s:%d: warning: discarding non-zero v2: %016lx\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, 0);}int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id){ int result; u64 v1; u64 v2; /* unused */ result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("id", 0), 0, 0, &v1, &v2); *bus_id = v1; return result;}int ps3_repository_read_bus_type(unsigned int bus_index, enum ps3_bus_type *bus_type){ int result; u64 v1; result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("type", 0), 0, 0, &v1, 0); *bus_type = v1; return result;}int ps3_repository_read_bus_num_dev(unsigned int bus_index, unsigned int *num_dev){ int result; u64 v1; result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("num_dev", 0), 0, 0, &v1, 0); *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, 0);}int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, unsigned int *dev_id){ int result; u64 v1; result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("id", 0), 0, &v1, 0); *dev_id = v1; 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; result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("type", 0), 0, &v1, 0); *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; u64 v2; 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; 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, 0); *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_debug("%s:%d read_bus_num_dev failed\n", __func__, __LINE__); return result; } pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %u, num_dev %u\n", __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, num_dev); if (tmp.dev_index >= num_dev) { pr_debug("%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_debug("%s:%d read_dev_type failed\n", __func__, __LINE__); return result; } if (tmp.bus_type == PS3_BUS_TYPE_STORAGE) { /* * A storage device may show up in the repository before the * hypervisor has finished probing its type and regions */ unsigned int num_regions; if (tmp.dev_type == PS3_DEV_TYPE_STOR_DUMMY) { pr_debug("%s:%u storage device not ready\n", __func__, __LINE__); return -ENODEV; } result = ps3_repository_read_stor_dev_num_regions(tmp.bus_index, tmp.dev_index, &num_regions); if (result) { pr_debug("%s:%d read_stor_dev_num_regions failed\n", __func__, __LINE__); return result; } if (!num_regions) { pr_debug("%s:%u storage device has no regions yet\n", __func__, __LINE__); return -ENODEV; } } result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, &tmp.dev_id); if (result) { pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, __LINE__); return result; } pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %u\n", __func__, __LINE__, tmp.dev_type, tmp.dev_index, 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_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { result = ps3_repository_read_bus_type(repo.bus_index, &repo.bus_type); if (result) { pr_debug("%s:%d read_bus_type(%u) failed\n", __func__, __LINE__, repo.bus_index); break; } if (repo.bus_type != bus_type) { pr_debug("%s:%d: skip, bus_type %u\n", __func__, __LINE__, repo.bus_type); continue; } result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id); if (result) { pr_debug("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__, repo.bus_index); continue; } 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_debug("%s:%d: abort at callback\n", __func__, __LINE__); break; } } break; } pr_debug(" <- %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_debug("%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_debug("%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_debug("%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_debug("%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_debug("%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_debug("%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_debug("%s:%d: found reg_type %u at res_index %u\n", __func__, __LINE__, reg_type, res_index);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -