aboutsummaryrefslogtreecommitdiffstats
path: root/xen
diff options
context:
space:
mode:
authorTim Deegan <tim@xen.org>2012-03-13 15:10:54 +0000
committerTim Deegan <tim@xen.org>2012-03-13 15:10:54 +0000
commit2ba79489668e8486341b24fd6efcfe5e7674a44c (patch)
treecb34ffd33051ba2fc7119f0a734a65597c77b300 /xen
parentd5e6a4f322ba4f7dc4b4fb721c164407b2d8a8d2 (diff)
downloadxen-2ba79489668e8486341b24fd6efcfe5e7674a44c.tar.gz
xen-2ba79489668e8486341b24fd6efcfe5e7674a44c.tar.bz2
xen-2ba79489668e8486341b24fd6efcfe5e7674a44c.zip
arm: per-cpu areas
Signed-off-by: Tim Deegan <tim@xen.org> Acked-by: Ian Campbell <ian.campbell@citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'xen')
-rw-r--r--xen/arch/arm/Makefile1
-rw-r--r--xen/arch/arm/dummy.S1
-rw-r--r--xen/arch/arm/percpu.c85
-rw-r--r--xen/arch/arm/setup.c4
-rw-r--r--xen/include/asm-arm/current.h4
-rw-r--r--xen/include/asm-arm/percpu.h7
6 files changed, 97 insertions, 5 deletions
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 4cb5d3a8e3..946a4ae48d 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -13,6 +13,7 @@ obj-y += irq.o
obj-y += kernel.o
obj-y += mm.o
obj-y += p2m.o
+obj-y += percpu.o
obj-y += guestcopy.o
obj-y += setup.o
obj-y += time.o
diff --git a/xen/arch/arm/dummy.S b/xen/arch/arm/dummy.S
index f096cb55dc..5f1fe2c462 100644
--- a/xen/arch/arm/dummy.S
+++ b/xen/arch/arm/dummy.S
@@ -14,7 +14,6 @@ DUMMY(per_cpu__cpu_core_mask);
DUMMY(per_cpu__cpu_sibling_mask);
DUMMY(node_online_map);
DUMMY(smp_send_state_dump);
-DUMMY(__per_cpu_offset);
/* PIRQ support */
DUMMY(alloc_pirq_struct);
diff --git a/xen/arch/arm/percpu.c b/xen/arch/arm/percpu.c
new file mode 100644
index 0000000000..e5450248ad
--- /dev/null
+++ b/xen/arch/arm/percpu.c
@@ -0,0 +1,85 @@
+#include <xen/config.h>
+#include <xen/percpu.h>
+#include <xen/cpu.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/rcupdate.h>
+
+unsigned long __per_cpu_offset[NR_CPUS];
+#define INVALID_PERCPU_AREA (-(long)__per_cpu_start)
+#define PERCPU_ORDER (get_order_from_bytes(__per_cpu_data_end-__per_cpu_start))
+
+void __init percpu_init_areas(void)
+{
+ unsigned int cpu;
+ for ( cpu = 1; cpu < NR_CPUS; cpu++ )
+ __per_cpu_offset[cpu] = INVALID_PERCPU_AREA;
+}
+
+static int init_percpu_area(unsigned int cpu)
+{
+ char *p;
+ if ( __per_cpu_offset[cpu] != INVALID_PERCPU_AREA )
+ return -EBUSY;
+ if ( (p = alloc_xenheap_pages(PERCPU_ORDER, 0)) == NULL )
+ return -ENOMEM;
+ memset(p, 0, __per_cpu_data_end - __per_cpu_start);
+ __per_cpu_offset[cpu] = p - __per_cpu_start;
+ return 0;
+}
+
+struct free_info {
+ unsigned int cpu;
+ struct rcu_head rcu;
+};
+static DEFINE_PER_CPU(struct free_info, free_info);
+
+static void _free_percpu_area(struct rcu_head *head)
+{
+ struct free_info *info = container_of(head, struct free_info, rcu);
+ unsigned int cpu = info->cpu;
+ char *p = __per_cpu_start + __per_cpu_offset[cpu];
+ free_xenheap_pages(p, PERCPU_ORDER);
+ __per_cpu_offset[cpu] = INVALID_PERCPU_AREA;
+}
+
+static void free_percpu_area(unsigned int cpu)
+{
+ struct free_info *info = &per_cpu(free_info, cpu);
+ info->cpu = cpu;
+ call_rcu(&info->rcu, _free_percpu_area);
+}
+
+static int cpu_percpu_callback(
+ struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ int rc = 0;
+
+ switch ( action )
+ {
+ case CPU_UP_PREPARE:
+ rc = init_percpu_area(cpu);
+ break;
+ case CPU_UP_CANCELED:
+ case CPU_DEAD:
+ free_percpu_area(cpu);
+ break;
+ default:
+ break;
+ }
+
+ return !rc ? NOTIFY_DONE : notifier_from_errno(rc);
+}
+
+static struct notifier_block cpu_percpu_nfb = {
+ .notifier_call = cpu_percpu_callback,
+ .priority = 100 /* highest priority */
+};
+
+static int __init percpu_presmp_init(void)
+{
+ register_cpu_notifier(&cpu_percpu_nfb);
+ return 0;
+}
+presmp_initcall(percpu_presmp_init);
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index f9f3a764f8..865f6fabae 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -182,6 +182,9 @@ void __init start_xen(unsigned long boot_phys_offset,
console_init_preirq();
#endif
+ percpu_init_areas();
+ set_processor_id(0); /* needed early, for smp_processor_id() */
+
cpus = gic_init();
printk("Waiting for %i other CPUs to be ready\n", cpus - 1);
@@ -200,7 +203,6 @@ void __init start_xen(unsigned long boot_phys_offset,
__set_current((struct vcpu *)0xfffff000); /* debug sanity */
idle_vcpu[0] = current;
- set_processor_id(0); /* needed early, for smp_processor_id() */
smp_prepare_cpus(max_cpus);
diff --git a/xen/include/asm-arm/current.h b/xen/include/asm-arm/current.h
index 72d494566b..bdce2d488b 100644
--- a/xen/include/asm-arm/current.h
+++ b/xen/include/asm-arm/current.h
@@ -40,7 +40,9 @@ static inline struct cpu_info *get_cpu_info(void)
#define get_current() (this_cpu(curr_vcpu))
#define __set_current(vcpu) (this_cpu(curr_vcpu) = (vcpu))
#define set_current(vcpu) do { \
- vcpu->arch.cpu_info->processor_id = get_processor_id(); \
+ int cpu = get_processor_id(); \
+ vcpu->arch.cpu_info->processor_id = cpu; \
+ vcpu->arch.cpu_info->per_cpu_offset = __per_cpu_offset[cpu]; \
__set_current(vcpu); \
} while (0)
#define current (get_current())
diff --git a/xen/include/asm-arm/percpu.h b/xen/include/asm-arm/percpu.h
index 9d369eb645..e832d6e426 100644
--- a/xen/include/asm-arm/percpu.h
+++ b/xen/include/asm-arm/percpu.h
@@ -12,8 +12,11 @@ void percpu_init_areas(void);
__attribute__((__section__(".bss.percpu" #suffix))) \
__typeof__(type) per_cpu_##name
-#define per_cpu(var, cpu) ((&per_cpu__##var)[cpu?0:0])
-#define __get_cpu_var(var) per_cpu__##var
+
+#define per_cpu(var, cpu) \
+ (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
+#define __get_cpu_var(var) \
+ (*RELOC_HIDE(&per_cpu__##var, get_cpu_info()->per_cpu_offset))
#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name