@@ -19,6 +19,7 @@
#include <linux/irqreturn.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/cpuidle.h>
@@ -48,8 +49,6 @@ struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata;
static __read_mostly unsigned int xen_events_irq;
-static __initdata struct device_node *xen_node;
-
int xen_remap_domain_gfn_array(struct vm_area_struct *vma,
unsigned long addr,
xen_pfn_t *gfn, int nr,
@@ -142,6 +141,34 @@ static irqreturn_t xen_arm_callback(int irq, void *arg)
return IRQ_HANDLED;
}
+struct xen_node_info {
+ const char *compat;
+ const char *prefix;
+ const char *version;
+ bool found;
+};
+
+static int __init fdt_find_xen_node(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ struct xen_node_info *info = data;
+ const void *s = NULL;
+ int len;
+
+ if (depth != 1 || strcmp(uname, "hypervisor") != 0)
+ return 0;
+
+ if (of_flat_dt_is_compatible(node, info->compat))
+ info->found = true;
+
+ s = of_get_flat_dt_prop(node, "compatible", &len);
+ if (strlen(info->prefix) + 3 < len &&
+ !strncmp(info->prefix, s, strlen(info->prefix)))
+ info->version = s + strlen(info->prefix);
+
+ return 0;
+}
+
/*
* see Documentation/devicetree/bindings/arm/xen.txt for the
* documentation of the Xen Device Tree format.
@@ -149,26 +176,25 @@ static irqreturn_t xen_arm_callback(int irq, void *arg)
#define GRANT_TABLE_PHYSADDR 0
void __init xen_early_init(void)
{
- int len;
- const char *s = NULL;
- const char *version = NULL;
- const char *xen_prefix = "xen,xen-";
+ struct xen_node_info info;
+
+ info.compat = "xen,xen";
+ info.prefix = "xen,xen-";
+ info.version = NULL;
+ info.found = false;
- xen_node = of_find_compatible_node(NULL, NULL, "xen,xen");
- if (!xen_node) {
+ of_scan_flat_dt(fdt_find_xen_node, &info);
+ if (!info.found) {
pr_debug("No Xen support\n");
return;
}
- s = of_get_property(xen_node, "compatible", &len);
- if (strlen(xen_prefix) + 3 < len &&
- !strncmp(xen_prefix, s, strlen(xen_prefix)))
- version = s + strlen(xen_prefix);
- if (version == NULL) {
+
+ if (info.version == NULL) {
pr_debug("Xen version not found\n");
return;
}
- pr_info("Xen %s support found\n", version);
+ pr_info("Xen %s support found\n", info.version);
xen_domain_type = XEN_HVM_DOMAIN;
@@ -204,6 +230,14 @@ static int __init xen_guest_init(void)
}
xen_events_irq = a.value & 0xff;
} else {
+ struct device_node *xen_node;
+
+ xen_node = of_find_compatible_node(NULL, NULL, "xen,xen");
+ if (!xen_node) {
+ pr_debug("No Xen support\n");
+ return -ENODEV;
+ }
+
xen_events_irq = irq_of_parse_and_map(xen_node, 0);
if (!xen_events_irq) {
pr_err("Xen event channel interrupt not found\n");
@@ -428,6 +428,7 @@ void __init setup_arch(char **cmdline_p)
*/
local_async_enable();
+ xen_early_init();
efi_init();
arm64_memblock_init();
@@ -446,7 +447,6 @@ void __init setup_arch(char **cmdline_p)
} else {
psci_acpi_init();
}
- xen_early_init();
cpu_read_bootcpu_ops();
smp_init_cpus();