Merge branch 'misc-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux
[pandora-kernel.git] / arch / arm / kernel / topology.c
1 /*
2  * arch/arm/kernel/topology.c
3  *
4  * Copyright (C) 2011 Linaro Limited.
5  * Written by: Vincent Guittot
6  *
7  * based on arch/sh/kernel/topology.c
8  *
9  * This file is subject to the terms and conditions of the GNU General Public
10  * License.  See the file "COPYING" in the main directory of this archive
11  * for more details.
12  */
13
14 #include <linux/cpu.h>
15 #include <linux/cpumask.h>
16 #include <linux/init.h>
17 #include <linux/percpu.h>
18 #include <linux/node.h>
19 #include <linux/nodemask.h>
20 #include <linux/sched.h>
21
22 #include <asm/cputype.h>
23 #include <asm/topology.h>
24
25 #define MPIDR_SMP_BITMASK (0x3 << 30)
26 #define MPIDR_SMP_VALUE (0x2 << 30)
27
28 #define MPIDR_MT_BITMASK (0x1 << 24)
29
30 /*
31  * These masks reflect the current use of the affinity levels.
32  * The affinity level can be up to 16 bits according to ARM ARM
33  */
34
35 #define MPIDR_LEVEL0_MASK 0x3
36 #define MPIDR_LEVEL0_SHIFT 0
37
38 #define MPIDR_LEVEL1_MASK 0xF
39 #define MPIDR_LEVEL1_SHIFT 8
40
41 #define MPIDR_LEVEL2_MASK 0xFF
42 #define MPIDR_LEVEL2_SHIFT 16
43
44 struct cputopo_arm cpu_topology[NR_CPUS];
45
46 const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
47 {
48         return &cpu_topology[cpu].core_sibling;
49 }
50
51 /*
52  * store_cpu_topology is called at boot when only one cpu is running
53  * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
54  * which prevents simultaneous write access to cpu_topology array
55  */
56 void store_cpu_topology(unsigned int cpuid)
57 {
58         struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
59         unsigned int mpidr;
60         unsigned int cpu;
61
62         /* If the cpu topology has been already set, just return */
63         if (cpuid_topo->core_id != -1)
64                 return;
65
66         mpidr = read_cpuid_mpidr();
67
68         /* create cpu topology mapping */
69         if ((mpidr & MPIDR_SMP_BITMASK) == MPIDR_SMP_VALUE) {
70                 /*
71                  * This is a multiprocessor system
72                  * multiprocessor format & multiprocessor mode field are set
73                  */
74
75                 if (mpidr & MPIDR_MT_BITMASK) {
76                         /* core performance interdependency */
77                         cpuid_topo->thread_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
78                                 & MPIDR_LEVEL0_MASK;
79                         cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
80                                 & MPIDR_LEVEL1_MASK;
81                         cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL2_SHIFT)
82                                 & MPIDR_LEVEL2_MASK;
83                 } else {
84                         /* largely independent cores */
85                         cpuid_topo->thread_id = -1;
86                         cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
87                                 & MPIDR_LEVEL0_MASK;
88                         cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
89                                 & MPIDR_LEVEL1_MASK;
90                 }
91         } else {
92                 /*
93                  * This is an uniprocessor system
94                  * we are in multiprocessor format but uniprocessor system
95                  * or in the old uniprocessor format
96                  */
97                 cpuid_topo->thread_id = -1;
98                 cpuid_topo->core_id = 0;
99                 cpuid_topo->socket_id = -1;
100         }
101
102         /* update core and thread sibling masks */
103         for_each_possible_cpu(cpu) {
104                 struct cputopo_arm *cpu_topo = &cpu_topology[cpu];
105
106                 if (cpuid_topo->socket_id == cpu_topo->socket_id) {
107                         cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
108                         if (cpu != cpuid)
109                                 cpumask_set_cpu(cpu,
110                                         &cpuid_topo->core_sibling);
111
112                         if (cpuid_topo->core_id == cpu_topo->core_id) {
113                                 cpumask_set_cpu(cpuid,
114                                         &cpu_topo->thread_sibling);
115                                 if (cpu != cpuid)
116                                         cpumask_set_cpu(cpu,
117                                                 &cpuid_topo->thread_sibling);
118                         }
119                 }
120         }
121         smp_wmb();
122
123         printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
124                 cpuid, cpu_topology[cpuid].thread_id,
125                 cpu_topology[cpuid].core_id,
126                 cpu_topology[cpuid].socket_id, mpidr);
127 }
128
129 /*
130  * init_cpu_topology is called at boot when only one cpu is running
131  * which prevent simultaneous write access to cpu_topology array
132  */
133 void init_cpu_topology(void)
134 {
135         unsigned int cpu;
136
137         /* init core mask */
138         for_each_possible_cpu(cpu) {
139                 struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
140
141                 cpu_topo->thread_id = -1;
142                 cpu_topo->core_id =  -1;
143                 cpu_topo->socket_id = -1;
144                 cpumask_clear(&cpu_topo->core_sibling);
145                 cpumask_clear(&cpu_topo->thread_sibling);
146         }
147         smp_wmb();
148 }