aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeelesh Gupta <neelegup@linux.vnet.ibm.com>2015-02-04 12:29:45 +0530
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-02-11 18:49:39 +1100
commit2e2acc7d9444742f0069811497efa8a194cb72c2 (patch)
treed24eaa6dec508eb5bae0cc8aaf3ab13e47ccfafb
parentde8bd4d09310f8307ffd1cee7d0f10b11c44fb60 (diff)
downloadskiboot-2e2acc7d9444742f0069811497efa8a194cb72c2.zip
skiboot-2e2acc7d9444742f0069811497efa8a194cb72c2.tar.gz
skiboot-2e2acc7d9444742f0069811497efa8a194cb72c2.tar.bz2
vpd: Use slca parent-child relationship to create vpd tree
SLCA entries available through hdat have parent-child relationship of various FRUs of the system, the patch makes use of this data to create VPD nodes in hierarchial fashion. This is further useful for the user space tools like 'lshw'/'lsvpd' to plug-in the support easily on POWER. Signed-off-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--hdata/spira.h2
-rw-r--r--hdata/vpd.c217
2 files changed, 77 insertions, 142 deletions
diff --git a/hdata/spira.h b/hdata/spira.h
index fa73452..a1ed79d 100644
--- a/hdata/spira.h
+++ b/hdata/spira.h
@@ -599,6 +599,8 @@ struct cpu_ctl_init_data {
*/
#define SLCA_IDATA_ARRAY 0
+#define SLCA_ROOT_INDEX 0
+
/* Note: An "index" (or idx) is always an index into the SLCA array
* and "id" is a reference to some other object.
*/
diff --git a/hdata/vpd.c b/hdata/vpd.c
index e568a06..38b0737 100644
--- a/hdata/vpd.c
+++ b/hdata/vpd.c
@@ -70,6 +70,9 @@ static const struct card_info card_table[] = {
/* Other cards */
};
+static struct dt_node *dt_create_vpd_node(struct dt_node *parent,
+ const struct slca_entry *entry);
+
static const struct card_info *card_info_lookup(char *ccin)
{
int i;
@@ -425,88 +428,6 @@ static const char *vpd_map_name(const char *vpd_name)
static bool valid_child_entry(const struct slca_entry *entry)
{
- if (!entry)
- return false;
-
- /*
- * Skip entries with independent ntuple FRUVPD/MSVPD, etc.,
- * representations, since they have a unique PN, FN, SN, et al.
- * We add details for those devices via the ntuple walk.
- */
- switch (entry->fru_id[0]) {
- case 'A':
- switch (entry->fru_id[1]) {
- case 'V': /* AV */
- return false;
- }
- break;
- case 'B':
- switch (entry->fru_id[1]) {
- case 'P': /* BP */
- case 'X': /* BX */
- return false;
- }
- break;
- case 'C':
- switch (entry->fru_id[1]) {
- case 'C': /* CC */
- return false;
- }
- break;
- case 'D':
- switch (entry->fru_id[1]) {
- case 'B': /* DB */
- return false;
- }
- break;
- case 'E':
- switch (entry->fru_id[1]) {
- case 'V': /* EV */
- return false;
- }
- break;
- case 'M':
- switch (entry->fru_id[1]) {
- case 'S': /* MS */
- return false;
- }
- break;
- case 'O':
- switch (entry->fru_id[1]) {
- case 'P': /* OP */
- return false;
- }
- break;
- case 'R':
- switch (entry->fru_id[1]) {
- case 'I': /* RI */
- return false;
- }
- break;
- case 'P':
- switch (entry->fru_id[1]) {
- case '2': /* P2 */
- case '5': /* P5 */
- case 'F': /* PF */
- return false;
- }
- break;
- case 'S':
- switch (entry->fru_id[1]) {
- case 'P': /* SP */
- return false;
- }
- break;
- case 'T':
- switch (entry->fru_id[1]) {
- case 'P': /* TP */
- return false;
- }
- break;
- default:
- break;
- }
-
if ((entry->install_indic == SLCA_INSTALL_INSTALLED) &&
(entry->vpd_collected == SLCA_VPD_COLLECTED))
return true;
@@ -546,26 +467,11 @@ static void vpd_add_children(struct dt_node *parent, uint16_t slca_index)
return;
if (valid_child_entry(child)) {
- const char *name;
- uint64_t addr;
struct dt_node *node;
- /* create new node, add location code */
- name = vpd_map_name(child->fru_id);
- addr = (uint64_t)be16_to_cpu(child->rsrc_id);
- node = dt_new_addr(parent, name, addr);
- if (!node) {
- prerror("VPD: Creating node at %s@%llx failed\n",
- name, addr);
+ node = dt_create_vpd_node(parent, child);
+ if (!node)
return;
- }
- slca_vpd_add_loc_code(node, be16_to_cpu(child->my_index));
-
- /* Add child FRU type */
- dt_add_property(node, "fru-type", child->fru_id, 2);
-
- /* recursively add children */
- vpd_add_children(node, be16_to_cpu(child->my_index));
}
/* Skip dups -- currently we presume dups are contiguous */
@@ -576,83 +482,110 @@ static void vpd_add_children(struct dt_node *parent, uint16_t slca_index)
return;
}
+/* Create the vpd node and add its children */
+static struct dt_node *dt_create_vpd_node(struct dt_node *parent,
+ const struct slca_entry *entry)
+{
+ struct dt_node *node;
+ const char *name;
+ uint64_t addr;
+
+ name = vpd_map_name(entry->fru_id);
+ addr = (uint64_t)be16_to_cpu(entry->rsrc_id);
+ node = dt_new_addr(parent, name, addr);
+ if (!node) {
+ prerror("VPD: Creating node at %s@%llx failed\n", name, addr);
+ return NULL;
+ }
+
+ /* Add location code */
+ slca_vpd_add_loc_code(node, be16_to_cpu(entry->my_index));
+ /* Add FRU label */
+ dt_add_property(node, "fru-type", entry->fru_id, 2);
+ /* Recursively add children */
+ vpd_add_children(node, be16_to_cpu(entry->my_index));
+
+ return node;
+}
+
struct dt_node *dt_add_vpd_node(const struct HDIF_common_hdr *hdr,
int indx_fru, int indx_vpd)
{
- const void *fruvpd;
- unsigned int fruvpd_sz;
- unsigned int fru_id_sz;
- uint64_t addr;
- struct dt_node *dt_vpd;
- struct dt_node *node;
const struct spira_fru_id *fru_id;
- const struct slca_entry *s_entry;
- const char *vpd_name;
+ unsigned int fruvpd_sz, fru_id_sz;
+ const struct slca_entry *entry;
+ struct dt_node *dt_vpd, *node;
+ static bool first = true;
+ const void *fruvpd;
const char *name;
- int len;
+ uint64_t addr;
char *lname;
+ int len;
fru_id = HDIF_get_idata(hdr, indx_fru, &fru_id_sz);
if (!fru_id)
return NULL;
- s_entry = slca_get_entry(be16_to_cpu(fru_id->slca_index));
- if (valid_child_entry(s_entry)) /* Don't populate child VPD here */
- return NULL;
-
fruvpd = HDIF_get_idata(hdr, indx_vpd, &fruvpd_sz);
if (!CHECK_SPPTR(fruvpd))
return NULL;
- vpd_name = slca_get_vpd_name(be16_to_cpu(fru_id->slca_index));
- if (!vpd_name) {
- prerror("VPD: VPD name at index %d couldn't be found\n",
- fru_id->slca_index);
+ dt_vpd = dt_find_by_path(dt_root, "/vpd");
+ if (!dt_vpd)
return NULL;
+
+ if (first) {
+ entry = slca_get_entry(SLCA_ROOT_INDEX);
+ if (!entry) {
+ prerror("VPD: Could not find the slca root entry\n");
+ return NULL;
+ }
+
+ node = dt_create_vpd_node(dt_vpd, entry);
+ if (!node)
+ return NULL;
+
+ first = false;
}
- dt_vpd = dt_find_by_path(dt_root, "/vpd");
- if (!dt_vpd)
+ entry = slca_get_entry(fru_id->slca_index);
+ if (!entry)
return NULL;
- /* Get node name */
- name = vpd_map_name(vpd_name);
- addr = (uint64_t)be16_to_cpu(fru_id->rsrc_id);
+ name = vpd_map_name(entry->fru_id);
+ addr = (uint64_t)be16_to_cpu(entry->rsrc_id);
len = strlen(name) + STR_MAX_CHARS(addr) + 2;
lname = zalloc(len);
if (!lname) {
prerror("VPD: Failed to allocate memory\n");
return NULL;
}
+
snprintf(lname, len, "%s@%llx", name, (long long)addr);
+ /* Get the node already created */
+ node = dt_find_by_name(dt_vpd, lname);
+ free(lname);
/*
- * FRU can be a child of some other FRU. Make sure
- * we have not added this node already.
+ * It is unlikely that node not found because vpd nodes have the
+ * corresponding slca entry which we would have used to populate the vpd
+ * tree during the 'first' pass above so that we just need to perform
+ * VINI parse and add the vpd data..
+ * Still, we consider this case and create fresh node under '/vpd' if
+ * 'node' not found.
*/
- node = dt_find_by_path(dt_vpd, lname);
- if (node) {
- free(lname);
- return NULL;
- }
-
- node = dt_new(dt_vpd, lname);
if (!node) {
- free(lname);
- return NULL;
+ node = dt_create_vpd_node(dt_vpd, entry);
+ if (!node)
+ return NULL;
}
- /* Parse VPD fields */
- dt_add_property(node, "ibm,vpd", fruvpd, fruvpd_sz);
- vpd_vini_parse(node, fruvpd, fruvpd_sz);
-
- /* Location code */
- slca_vpd_add_loc_code(node, be16_to_cpu(fru_id->slca_index));
- /* Add FRU label */
- dt_add_property(node, "fru-type", vpd_name, 2);
- vpd_add_children(node, be16_to_cpu(fru_id->slca_index));
+ /* Parse VPD fields, ensure that it has not been added already */
+ if (!dt_find_property(node, "ibm,vpd")) {
+ dt_add_property(node, "ibm,vpd", fruvpd, fruvpd_sz);
+ vpd_vini_parse(node, fruvpd, fruvpd_sz);
+ }
- free(lname);
return node;
}