1 #include <xen/percpu.h>
2 #include <xen/cpu.h>
3 #include <xen/init.h>
4 #include <xen/mm.h>
5 #include <xen/rcupdate.h>
6 
7 unsigned long __per_cpu_offset[NR_CPUS];
8 #define INVALID_PERCPU_AREA (-(long)__per_cpu_start)
9 #define PERCPU_ORDER (get_order_from_bytes(__per_cpu_data_end-__per_cpu_start))
10 
percpu_init_areas(void)11 void __init percpu_init_areas(void)
12 {
13     unsigned int cpu;
14     for ( cpu = 1; cpu < NR_CPUS; cpu++ )
15         __per_cpu_offset[cpu] = INVALID_PERCPU_AREA;
16 }
17 
init_percpu_area(unsigned int cpu)18 static int init_percpu_area(unsigned int cpu)
19 {
20     char *p;
21     if ( __per_cpu_offset[cpu] != INVALID_PERCPU_AREA )
22         return -EBUSY;
23     if ( (p = alloc_xenheap_pages(PERCPU_ORDER, 0)) == NULL )
24         return -ENOMEM;
25     memset(p, 0, __per_cpu_data_end - __per_cpu_start);
26     __per_cpu_offset[cpu] = p - __per_cpu_start;
27     return 0;
28 }
29 
30 struct free_info {
31     unsigned int cpu;
32     struct rcu_head rcu;
33 };
34 static DEFINE_PER_CPU(struct free_info, free_info);
35 
_free_percpu_area(struct rcu_head * head)36 static void _free_percpu_area(struct rcu_head *head)
37 {
38     struct free_info *info = container_of(head, struct free_info, rcu);
39     unsigned int cpu = info->cpu;
40     char *p = __per_cpu_start + __per_cpu_offset[cpu];
41     free_xenheap_pages(p, PERCPU_ORDER);
42     __per_cpu_offset[cpu] = INVALID_PERCPU_AREA;
43 }
44 
free_percpu_area(unsigned int cpu)45 static void free_percpu_area(unsigned int cpu)
46 {
47     struct free_info *info = &per_cpu(free_info, cpu);
48     info->cpu = cpu;
49     call_rcu(&info->rcu, _free_percpu_area);
50 }
51 
cpu_percpu_callback(struct notifier_block * nfb,unsigned long action,void * hcpu)52 static int cpu_percpu_callback(
53     struct notifier_block *nfb, unsigned long action, void *hcpu)
54 {
55     unsigned int cpu = (unsigned long)hcpu;
56     int rc = 0;
57 
58     switch ( action )
59     {
60     case CPU_UP_PREPARE:
61         rc = init_percpu_area(cpu);
62         break;
63     case CPU_UP_CANCELED:
64     case CPU_DEAD:
65         free_percpu_area(cpu);
66         break;
67     default:
68         break;
69     }
70 
71     return !rc ? NOTIFY_DONE : notifier_from_errno(rc);
72 }
73 
74 static struct notifier_block cpu_percpu_nfb = {
75     .notifier_call = cpu_percpu_callback,
76     .priority = 100 /* highest priority */
77 };
78 
percpu_presmp_init(void)79 static int __init percpu_presmp_init(void)
80 {
81     register_cpu_notifier(&cpu_percpu_nfb);
82     return 0;
83 }
84 presmp_initcall(percpu_presmp_init);
85