aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.vnet.ibm.com>2018-01-05 10:56:33 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2018-01-05 10:56:33 +1100
commit72d84a42c45c49cc5c502a9e1d6724fa13858cd2 (patch)
treec9a1a0d6c79e06f90cdc136e71e8380fc447e21c
parentfd2fbffd8c4eb15e3f118e647c4cbfa13a324784 (diff)
parent9fe72fc36d209d92ff745e7582a109b025997244 (diff)
downloadskiboot-72d84a42c45c49cc5c502a9e1d6724fa13858cd2.zip
skiboot-72d84a42c45c49cc5c502a9e1d6724fa13858cd2.tar.gz
skiboot-72d84a42c45c49cc5c502a9e1d6724fa13858cd2.tar.bz2
Merge skiboot-5.4.9 into 5.4.x
-rw-r--r--core/device.c14
-rw-r--r--core/opal.c6
-rw-r--r--hdata/hdif.c70
-rw-r--r--hdata/hdif.h18
-rw-r--r--hdata/spira.c47
-rw-r--r--hdata/spira.h7
-rw-r--r--include/device.h1
7 files changed, 158 insertions, 5 deletions
diff --git a/core/device.c b/core/device.c
index 63b5df8..a9c7ebe 100644
--- a/core/device.c
+++ b/core/device.c
@@ -352,6 +352,20 @@ struct dt_node *dt_find_by_name(struct dt_node *root, const char *name)
return NULL;
}
+
+struct dt_node *dt_new_check(struct dt_node *parent, const char *name)
+{
+ struct dt_node *node = dt_find_by_name(parent, name);
+
+ if (!node) {
+ node = dt_new(parent, name);
+ assert(node);
+ }
+
+ return node;
+}
+
+
struct dt_node *dt_find_by_phandle(struct dt_node *root, u32 phandle)
{
struct dt_node *node;
diff --git a/core/opal.c b/core/opal.c
index 14e78c0..9936dcc 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -161,11 +161,7 @@ void add_opal_node(void)
size = (CPU_STACKS_BASE +
(uint64_t)(cpu_max_pir + 1) * STACK_SIZE) - SKIBOOT_BASE;
- if (!opal_node) {
- opal_node = dt_new(dt_root, "ibm,opal");
- assert(opal_node);
- }
-
+ opal_node = dt_new_check(dt_root, "ibm,opal");
dt_add_property_cells(opal_node, "#address-cells", 0);
dt_add_property_cells(opal_node, "#size-cells", 0);
diff --git a/hdata/hdif.c b/hdata/hdif.c
index 25c0000..99ffee5 100644
--- a/hdata/hdif.c
+++ b/hdata/hdif.c
@@ -15,6 +15,7 @@
*/
#include "hdif.h"
+#include "stack.h"
const void *HDIF_get_idata(const struct HDIF_common_hdr *hdif, unsigned int di,
unsigned int *size)
@@ -90,6 +91,75 @@ int HDIF_get_iarray_size(const struct HDIF_common_hdr *hdif, unsigned int di)
return be32_to_cpu(ahdr->ecnt);
}
+/*
+ * Returns NULL and sets *items to zero when:
+ *
+ * a) Array extends beyond bounds (hard error)
+ * b) The array is empty (soft error)
+ * c) The item size is zero (soft error)
+ * d) The array is missing (soft error)
+ *
+ * b, c) are bugs in the input data so they generate backtraces.
+ *
+ * If you care about the soft error cases, retrive the array header manually
+ * with HDIF_get_idata().
+ */
+const struct HDIF_array_hdr *HDIF_get_iarray(const struct HDIF_common_hdr *hdif,
+ unsigned int di, unsigned int *items)
+{
+ const struct HDIF_array_hdr *arr;
+ unsigned int req_size, size, elements;
+ unsigned int actual_sz, alloc_sz, offset;
+
+ arr = HDIF_get_idata(hdif, di, &size);
+
+ if(items)
+ *items = 0;
+
+ if (!arr || !size)
+ return NULL;
+
+ /* base size of an Idata array header */
+ offset = be32_to_cpu(arr->offset);
+ actual_sz = be32_to_cpu(arr->eactsz);
+ alloc_sz = be32_to_cpu(arr->esize);
+ elements = be32_to_cpu(arr->ecnt);
+
+ /* actual size should always be smaller than allocated */
+ if (alloc_sz < actual_sz) {
+ prerror("HDIF %.6s iarray %u has actsz (%u) < alloc_sz (%u)\n)",
+ hdif->id, di, actual_sz, alloc_sz);
+ backtrace();
+ return NULL;
+ }
+
+ req_size = elements * alloc_sz + offset;
+ if (req_size > size) {
+ prerror("HDIF: %.6s iarray %u requires %#x bytes, but only %#x are allocated!\n",
+ hdif->id, di, req_size, size);
+ backtrace();
+ return NULL;
+ }
+
+ if (!elements || !actual_sz)
+ return NULL;
+
+ if (items)
+ *items = elements;
+
+ return arr;
+}
+
+const void *HDIF_iarray_item(const struct HDIF_array_hdr *ahdr,
+ unsigned int index)
+{
+ if (!ahdr || index >= be32_to_cpu(ahdr->ecnt))
+ return NULL;
+
+ return (const void * )ahdr + be32_to_cpu(ahdr->offset) +
+ index * be32_to_cpu(ahdr->esize);
+}
+
struct HDIF_child_ptr *
HDIF_child_arr(const struct HDIF_common_hdr *hdif, unsigned int idx)
{
diff --git a/hdata/hdif.h b/hdata/hdif.h
index ef03522..447ef4b 100644
--- a/hdata/hdif.h
+++ b/hdata/hdif.h
@@ -105,6 +105,24 @@ extern const void *HDIF_get_iarray_item(const struct HDIF_common_hdr *hdif,
unsigned int di,
unsigned int ai, unsigned int *size);
+/* HDIF_get_iarray - Get a pointer to an internal array header
+ *
+ * @hdif : HDIF structure pointer
+ * @di : Index of the idata pointer
+ * @ai : Index in the resulting array
+ * @size : Return the entry actual size (or NULL if ignored)
+ */
+extern const struct HDIF_array_hdr *HDIF_get_iarray(
+ const struct HDIF_common_hdr *hdif, unsigned int di,
+ unsigned int *items);
+
+extern const void *HDIF_iarray_item(const struct HDIF_array_hdr *hdif,
+ unsigned int index);
+
+#define HDIF_iarray_for_each(arr, idx, ptr) \
+ for (idx = 0, ptr = HDIF_iarray_item(arr, idx); \
+ ptr; idx++, ptr = HDIF_iarray_item(arr, idx))
+
/* HDIF_get_iarray_size - Get the number of elements of an internal data array
*
* @hdif : HDIF structure pointer
diff --git a/hdata/spira.c b/hdata/spira.c
index 592197e..428b3e0 100644
--- a/hdata/spira.c
+++ b/hdata/spira.c
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <inttypes.h>
#include <device.h>
#include "spira.h"
#include <cpu.h>
@@ -916,6 +917,51 @@ static void add_iplparams_platform_dump(const void *iplp, struct dt_node *node)
}
}
+static void add_iplparams_features(const struct HDIF_common_hdr *iplp)
+{
+ const struct iplparams_feature *feature;
+ const struct HDIF_array_hdr *array;
+ struct dt_node *fw_features;
+ unsigned int count, i;
+ char name[65];
+
+ array = HDIF_get_iarray(iplp, IPLPARAMS_FEATURES, &count);
+ if (!array || !count)
+ return;
+
+ opal_node = dt_new_check(dt_root, "ibm,opal");
+ fw_features = dt_new(opal_node, "fw-features");
+ if (!fw_features)
+ return;
+
+ HDIF_iarray_for_each(array, i, feature) {
+ struct dt_node *n;
+ uint64_t flags;
+
+ /* the name field isn't necessarily null terminated */
+ strncpy(name, feature->name, sizeof(feature->name));
+ flags = be64_to_cpu(feature->flags);
+
+ prlog(PR_DEBUG, "IPLPARAMS: FW feature %s = %016"PRIx64"\n",
+ name, flags);
+
+ /* get rid of tm-suspend-mode-enabled being disabled */
+ if (strcmp(name, "tm-suspend-mode-enabled") == 0)
+ strcpy(name, "tm-suspend-mode");
+
+ n = dt_new(fw_features, name);
+
+ /*
+ * This is a bit overkill, but we'll want seperate properties
+ * for each flag bit(s).
+ */
+ if (flags & PPC_BIT(0))
+ dt_add_property(n, "enabled", NULL, 0);
+ else
+ dt_add_property(n, "disabled", NULL, 0);
+ }
+}
+
static void add_iplparams(void)
{
struct dt_node *iplp_node;
@@ -936,6 +982,7 @@ static void add_iplparams(void)
add_iplparams_ipl_params(ipl_parms, iplp_node);
add_iplparams_serials(ipl_parms, iplp_node);
add_iplparams_platform_dump(ipl_parms, iplp_node);
+ add_iplparams_features(ipl_parms);
}
/* Various structure contain a "proc_chip_id" which is an arbitrary
diff --git a/hdata/spira.h b/hdata/spira.h
index eabf7f9..7fdc2d0 100644
--- a/hdata/spira.h
+++ b/hdata/spira.h
@@ -380,6 +380,13 @@ struct iplparms_serial {
#define PLPARMS_SERIAL_FLAGS_CALLHOME 0x8000
} __packed;
+/* Idata index 9: FW features */
+#define IPLPARAMS_FEATURES 9
+struct iplparams_feature {
+ char name[64];
+ __be64 flags;
+} __packed;
+
/*
* Chip TOD structure
*
diff --git a/include/device.h b/include/device.h
index 4198a41..1ad403f 100644
--- a/include/device.h
+++ b/include/device.h
@@ -67,6 +67,7 @@ struct dt_node *dt_new_addr(struct dt_node *parent, const char *name,
uint64_t unit_addr);
struct dt_node *dt_new_2addr(struct dt_node *parent, const char *name,
uint64_t unit_addr0, uint64_t unit_addr1);
+struct dt_node *dt_new_check(struct dt_node *parent, const char *name);
/* Copy node to new parent, including properties and subnodes */
struct dt_node *dt_copy(struct dt_node *node, struct dt_node *parent);