diff options
Diffstat (limited to 'hdata/hostservices.c')
-rw-r--r-- | hdata/hostservices.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/hdata/hostservices.c b/hdata/hostservices.c new file mode 100644 index 0000000..ff2edbe --- /dev/null +++ b/hdata/hostservices.c @@ -0,0 +1,96 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> + +#include <libfdt/libfdt.h> +#include <skiboot.h> +#include <device.h> +#include <compiler.h> +#include <hostservices.h> + +#include "spira.h" +#include "hdata.h" + +static void merge_property(const struct dt_node *src_root, + struct dt_node *dst_root, + const char *name) +{ + const struct dt_property *src; + struct dt_property *dst; + + /* Nothing to merge if old one doesn't exist. */ + src = dt_find_property(src_root, name); + if (!src) + return; + + /* Just create a new one if there's none in dst. */ + dst = __dt_find_property(dst_root, name); + if (!dst) { + dt_add_property(dst_root, name, src->prop, src->len); + return; + } + + /* Append src to dst. */ + dt_resize_property(&dst, dst->len + src->len); + memcpy(dst->prop + dst->len, src->prop, src->len); + dst->len += src->len; +} + +static void hservice_parse_dt_tree(const struct dt_node *src) +{ + const struct dt_property *sprop; + + /* Copy/merge reserved names & ranges properties. */ + list_for_each(&src->properties, sprop, list) { + if (streq(sprop->name, "reserved-names") || + streq(sprop->name, "reserved-ranges") || + streq(sprop->name, "ibm,enabled-idle-states")) + merge_property(src, dt_root, sprop->name); + } +} + +/* Get host services information from hdat. */ +bool hservices_from_hdat(const void *fdt, size_t size) +{ + int err; + struct dt_node *hservices; + + printf("HBRT: Found mini-DT at 0x%p size: 0x%08lx\n", fdt, size); + + /* For diagnostic purposes, we copy the whole blob over */ + dt_add_property(dt_root, "ibm,hbrt-mini-fdt", fdt, size); + + /* Parse & extract relevant properties */ + err = fdt_check_header(fdt); + if (err) { + prerror("HBRT: fdt blob %p hdr error %d\n", fdt, err); + return false; + } + + hservices = dt_new_root("ibm,hostservices"); + err = dt_expand_node(hservices, fdt, 0); + if (err < 0) { + prerror("HBRT: fdt blob %p parse error %d\n", fdt, err); + return false; + } + + hservice_parse_dt_tree(hservices); + return true; +} + |