diff options
author | Stewart Smith <stewart@linux.vnet.ibm.com> | 2018-01-05 10:56:33 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2018-01-05 10:56:33 +1100 |
commit | 72d84a42c45c49cc5c502a9e1d6724fa13858cd2 (patch) | |
tree | c9a1a0d6c79e06f90cdc136e71e8380fc447e21c | |
parent | fd2fbffd8c4eb15e3f118e647c4cbfa13a324784 (diff) | |
parent | 9fe72fc36d209d92ff745e7582a109b025997244 (diff) | |
download | skiboot-72d84a42c45c49cc5c502a9e1d6724fa13858cd2.zip skiboot-72d84a42c45c49cc5c502a9e1d6724fa13858cd2.tar.gz skiboot-72d84a42c45c49cc5c502a9e1d6724fa13858cd2.tar.bz2 |
Merge skiboot-5.4.9 into 5.4.x
-rw-r--r-- | core/device.c | 14 | ||||
-rw-r--r-- | core/opal.c | 6 | ||||
-rw-r--r-- | hdata/hdif.c | 70 | ||||
-rw-r--r-- | hdata/hdif.h | 18 | ||||
-rw-r--r-- | hdata/spira.c | 47 | ||||
-rw-r--r-- | hdata/spira.h | 7 | ||||
-rw-r--r-- | include/device.h | 1 |
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); |