aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>2012-11-19 12:59:46 +0000
committerStefano Stabellini <stefano.stabellini@eu.citrix.com>2012-11-19 12:59:46 +0000
commit2ac19a6b381c9a9cd57afc107af95761bbddb5e0 (patch)
tree8d77dcf094bf9fee96fe09d6737040fc38ce1a89
parenta8c81103334f89bf3bfc051201e4b5717a014d4d (diff)
downloadxen-2ac19a6b381c9a9cd57afc107af95761bbddb5e0.tar.gz
xen-2ac19a6b381c9a9cd57afc107af95761bbddb5e0.tar.bz2
xen-2ac19a6b381c9a9cd57afc107af95761bbddb5e0.zip
xen/arm: get the number of cpus from device tree
The system might have fewer cpus than the GIC supports. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
-rw-r--r--xen/arch/arm/gic.c4
-rw-r--r--xen/arch/arm/gic.h2
-rw-r--r--xen/arch/arm/setup.c5
-rw-r--r--xen/arch/arm/smpboot.c27
-rw-r--r--xen/common/device_tree.c43
-rw-r--r--xen/include/asm-arm/smp.h2
6 files changed, 71 insertions, 12 deletions
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 5f06e085e0..0c6fab9151 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -304,7 +304,7 @@ static void __cpuinit gic_hyp_disable(void)
}
/* Set up the GIC */
-int __init gic_init(void)
+void __init gic_init(void)
{
/* XXX FIXME get this from devicetree */
gic.dbase = GIC_BASE_ADDRESS + GIC_DR_OFFSET;
@@ -328,8 +328,6 @@ int __init gic_init(void)
gic.lr_mask = 0ULL;
spin_unlock(&gic.lock);
-
- return gic.cpus;
}
/* Set up the per-CPU parts of the GIC for a secondary CPU */
diff --git a/xen/arch/arm/gic.h b/xen/arch/arm/gic.h
index b2e1d7face..1bf1b02913 100644
--- a/xen/arch/arm/gic.h
+++ b/xen/arch/arm/gic.h
@@ -147,7 +147,7 @@ extern int gic_route_irq_to_guest(struct domain *d, unsigned int irq,
/* Accept an interrupt from the GIC and dispatch its handler */
extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq);
/* Bring up the interrupt controller, and report # cpus attached */
-extern int gic_init(void);
+extern void gic_init(void);
/* Bring up a secondary CPU's per-CPU GIC interface */
extern void gic_init_secondary_cpu(void);
/* Take down a CPU's per-CPU GIC interface */
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 0328394179..c52330ee84 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -185,10 +185,13 @@ void __init start_xen(unsigned long boot_phys_offset,
size_t fdt_size;
int cpus, i;
+ smp_clear_cpu_maps();
+
fdt = (void *)BOOT_MISC_VIRT_START
+ (atag_paddr & ((1 << SECOND_SHIFT) - 1));
fdt_size = device_tree_early_init(fdt);
+ cpus = smp_get_max_cpus();
cmdline_parse(device_tree_bootargs(fdt));
setup_pagetables(boot_phys_offset, get_xen_paddr());
@@ -199,7 +202,7 @@ void __init start_xen(unsigned long boot_phys_offset,
console_init_preirq();
#endif
- cpus = gic_init();
+ gic_init();
make_cpus_ready(cpus, boot_phys_offset);
percpu_init_areas();
diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
index 1b52e22c4a..05c8d8d22c 100644
--- a/xen/arch/arm/smpboot.c
+++ b/xen/arch/arm/smpboot.c
@@ -71,18 +71,31 @@ static void setup_cpu_sibling_map(int cpu)
cpumask_set_cpu(cpu, per_cpu(cpu_core_mask, cpu));
}
-
void __init
-smp_prepare_cpus (unsigned int max_cpus)
+smp_clear_cpu_maps (void)
{
- int i;
-
+ cpumask_clear(&cpu_possible_map);
cpumask_clear(&cpu_online_map);
cpumask_set_cpu(0, &cpu_online_map);
+ cpumask_set_cpu(0, &cpu_possible_map);
+}
- cpumask_clear(&cpu_possible_map);
- for ( i = 0; i < max_cpus; i++ )
- cpumask_set_cpu(i, &cpu_possible_map);
+int __init
+smp_get_max_cpus (void)
+{
+ int i, max_cpus = 0;
+
+ for ( i = 0; i < nr_cpu_ids; i++ )
+ if ( cpu_possible(i) )
+ max_cpus++;
+
+ return max_cpus;
+}
+
+
+void __init
+smp_prepare_cpus (unsigned int max_cpus)
+{
cpumask_copy(&cpu_present_map, &cpu_possible_map);
setup_cpu_sibling_map(0);
diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index 3d1f0f45fc..da0af77d77 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -18,6 +18,7 @@
#include <xen/mm.h>
#include <xen/stdarg.h>
#include <xen/string.h>
+#include <xen/cpumask.h>
#include <asm/early_printk.h>
struct dt_early_info __initdata early_info;
@@ -41,6 +42,18 @@ bool_t device_tree_node_matches(const void *fdt, int node, const char *match)
&& (name[match_len] == '@' || name[match_len] == '\0');
}
+bool_t device_tree_type_matches(const void *fdt, int node, const char *match)
+{
+ int len;
+ const void *prop;
+
+ prop = fdt_getprop(fdt, node, "device_type", &len);
+ if ( prop == NULL )
+ return 0;
+
+ return !strncmp(prop, match, len);
+}
+
static void __init get_val(const u32 **cell, u32 cells, u64 *val)
{
*val = 0;
@@ -229,6 +242,34 @@ static void __init process_memory_node(const void *fdt, int node,
}
}
+static void __init process_cpu_node(const void *fdt, int node,
+ const char *name,
+ u32 address_cells, u32 size_cells)
+{
+ const struct fdt_property *prop;
+ const u32 *cell;
+ paddr_t start, size;
+
+ if ( address_cells != 1 || size_cells != 0 )
+ {
+ early_printk("fdt: node `%s': invalid #address-cells or #size-cells",
+ name);
+ return;
+ }
+
+ prop = fdt_get_property(fdt, node, "reg", NULL);
+ if ( !prop )
+ {
+ early_printk("fdt: node `%s': missing `reg' property\n", name);
+ return;
+ }
+
+ cell = (const u32 *)prop->data;
+ device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
+
+ cpumask_set_cpu(start, &cpu_possible_map);
+}
+
static int __init early_scan_node(const void *fdt,
int node, const char *name, int depth,
u32 address_cells, u32 size_cells,
@@ -236,6 +277,8 @@ static int __init early_scan_node(const void *fdt,
{
if ( device_tree_node_matches(fdt, node, "memory") )
process_memory_node(fdt, node, name, address_cells, size_cells);
+ else if ( device_tree_type_matches(fdt, node, "cpu") )
+ process_cpu_node(fdt, node, name, address_cells, size_cells);
return 0;
}
diff --git a/xen/include/asm-arm/smp.h b/xen/include/asm-arm/smp.h
index a98032dc2c..d4ed1cb2fd 100644
--- a/xen/include/asm-arm/smp.h
+++ b/xen/include/asm-arm/smp.h
@@ -22,6 +22,8 @@ extern void stop_cpu(void);
extern void
make_cpus_ready(unsigned int max_cpus, unsigned long boot_phys_offset);
+extern void smp_clear_cpu_maps (void);
+extern int smp_get_max_cpus (void);
#endif
/*
* Local variables: