hw/arm/sysbus-fdt: helpers for clock node generation

Some passthrough'ed devices depend on clock nodes. Those need to be
generated in the guest device tree. This patch introduces some helpers
to build a clock node from information retrieved in the host device tree.

- copy_properties_from_host copies properties from a host device tree
  node to a guest device tree node
- fdt_build_clock_node builds a guest clock node and checks the host
  fellow clock is a fixed one.

fdt_build_clock_node will become static as soon as it gets used. A
dummy pre-declaration is needed for compilation of this patch.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
Eric Auger 2016-02-19 09:42:31 -07:00 committed by Alex Williamson
parent 58e71097ce
commit 9481cf2e5f
1 changed files with 120 additions and 0 deletions

View File

@ -22,6 +22,7 @@
*/
#include "qemu/osdep.h"
#include <libfdt.h>
#include "hw/arm/sysbus-fdt.h"
#include "qemu/error-report.h"
#include "sysemu/device_tree.h"
@ -57,6 +58,125 @@ typedef struct NodeCreationPair {
int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
} NodeCreationPair;
/* helpers */
typedef struct HostProperty {
const char *name;
bool optional;
} HostProperty;
/**
* copy_properties_from_host
*
* copies properties listed in an array from host device tree to
* guest device tree. If a non optional property is not found, the
* function asserts. An optional property is ignored if not found
* in the host device tree.
* @props: array of HostProperty to copy
* @nb_props: number of properties in the array
* @host_dt: host device tree blob
* @guest_dt: guest device tree blob
* @node_path: host dt node path where the property is supposed to be
found
* @nodename: guest node name the properties should be added to
*/
static void copy_properties_from_host(HostProperty *props, int nb_props,
void *host_fdt, void *guest_fdt,
char *node_path, char *nodename)
{
int i, prop_len;
const void *r;
Error *err = NULL;
for (i = 0; i < nb_props; i++) {
r = qemu_fdt_getprop(host_fdt, node_path,
props[i].name,
&prop_len,
props[i].optional ? &err : &error_fatal);
if (r) {
qemu_fdt_setprop(guest_fdt, nodename,
props[i].name, r, prop_len);
} else {
if (prop_len != -FDT_ERR_NOTFOUND) {
/* optional property not returned although property exists */
error_report_err(err);
} else {
error_free(err);
}
}
}
}
/* clock properties whose values are copied/pasted from host */
static HostProperty clock_copied_properties[] = {
{"compatible", false},
{"#clock-cells", false},
{"clock-frequency", true},
{"clock-output-names", true},
};
/**
* fdt_build_clock_node
*
* Build a guest clock node, used as a dependency from a passthrough'ed
* device. Most information are retrieved from the host clock node.
* Also check the host clock is a fixed one.
*
* @host_fdt: host device tree blob from which info are retrieved
* @guest_fdt: guest device tree blob where the clock node is added
* @host_phandle: phandle of the clock in host device tree
* @guest_phandle: phandle to assign to the guest node
*/
void fdt_build_clock_node(void *host_fdt, void *guest_fdt,
uint32_t host_phandle,
uint32_t guest_phandle);
void fdt_build_clock_node(void *host_fdt, void *guest_fdt,
uint32_t host_phandle,
uint32_t guest_phandle)
{
char *node_path = NULL;
char *nodename;
const void *r;
int ret, node_offset, prop_len, path_len = 16;
node_offset = fdt_node_offset_by_phandle(host_fdt, host_phandle);
if (node_offset <= 0) {
error_setg(&error_fatal,
"not able to locate clock handle %d in host device tree",
host_phandle);
}
node_path = g_malloc(path_len);
while ((ret = fdt_get_path(host_fdt, node_offset, node_path, path_len))
== -FDT_ERR_NOSPACE) {
path_len += 16;
node_path = g_realloc(node_path, path_len);
}
if (ret < 0) {
error_setg(&error_fatal,
"not able to retrieve node path for clock handle %d",
host_phandle);
}
r = qemu_fdt_getprop(host_fdt, node_path, "compatible", &prop_len,
&error_fatal);
if (strcmp(r, "fixed-clock")) {
error_setg(&error_fatal,
"clock handle %d is not a fixed clock", host_phandle);
}
nodename = strrchr(node_path, '/');
qemu_fdt_add_subnode(guest_fdt, nodename);
copy_properties_from_host(clock_copied_properties,
ARRAY_SIZE(clock_copied_properties),
host_fdt, guest_fdt,
node_path, nodename);
qemu_fdt_setprop_cell(guest_fdt, nodename, "phandle", guest_phandle);
g_free(node_path);
}
/* Device Specific Code */
/**