Blame view

arch/x86/kernel/apic/x2apic_cluster.c 6.83 KB
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
1
2
3
4
5
6
  #include <linux/threads.h>
  #include <linux/cpumask.h>
  #include <linux/string.h>
  #include <linux/kernel.h>
  #include <linux/ctype.h>
  #include <linux/init.h>
1b9b89e7f   Yinghai Lu   x86: add apic pro...
7
  #include <linux/dmar.h>
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
8
  #include <linux/cpu.h>
1b9b89e7f   Yinghai Lu   x86: add apic pro...
9

12a67cf68   Suresh Siddha   x64, x2apic/intr-...
10
  #include <asm/smp.h>
79deb8e51   Cyrill Gorcunov   x86, x2apic: Move...
11
  #include <asm/x2apic.h>
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
12

2de1f33e9   Jaswinder Singh Rajput   x86: apic/x2apic_...
13
  static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
14
  static DEFINE_PER_CPU(cpumask_var_t, cpus_in_cluster);
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
15
  static DEFINE_PER_CPU(cpumask_var_t, ipi_mask);
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
16

2caa37150   Marcin Slusarz   x86: fix section ...
17
  static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
1b9b89e7f   Yinghai Lu   x86: add apic pro...
18
  {
ef1f87aa7   Suresh Siddha   x86: select x2api...
19
  	return x2apic_enabled();
1b9b89e7f   Yinghai Lu   x86: add apic pro...
20
  }
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
21
22
23
24
  static inline u32 x2apic_cluster(int cpu)
  {
  	return per_cpu(x86_cpu_to_logical_apicid, cpu) >> 16;
  }
a27d0b5e7   Suresh Siddha   x86, x2apic: Remo...
25
26
  static void
  __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
27
  {
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
28
29
30
  	struct cpumask *cpus_in_cluster_ptr;
  	struct cpumask *ipi_mask_ptr;
  	unsigned int cpu, this_cpu;
dac5f4121   Ingo Molnar   x86, apic: untang...
31
  	unsigned long flags;
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
32
  	u32 dest;
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
33

ce4e240c2   Suresh Siddha   x86: add x2apic_w...
34
  	x2apic_wrmsr_fence();
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
35
  	local_irq_save(flags);
a27d0b5e7   Suresh Siddha   x86, x2apic: Remo...
36
37
  
  	this_cpu = smp_processor_id();
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  
  	/*
  	 * We are to modify mask, so we need an own copy
  	 * and be sure it's manipulated with irq off.
  	 */
  	ipi_mask_ptr = __raw_get_cpu_var(ipi_mask);
  	cpumask_copy(ipi_mask_ptr, mask);
  
  	/*
  	 * The idea is to send one IPI per cluster.
  	 */
  	for_each_cpu(cpu, ipi_mask_ptr) {
  		unsigned long i;
  
  		cpus_in_cluster_ptr = per_cpu(cpus_in_cluster, cpu);
  		dest = 0;
  
  		/* Collect cpus in cluster. */
  		for_each_cpu_and(i, ipi_mask_ptr, cpus_in_cluster_ptr) {
  			if (apic_dest == APIC_DEST_ALLINC || i != this_cpu)
  				dest |= per_cpu(x86_cpu_to_logical_apicid, i);
  		}
  
  		if (!dest)
a27d0b5e7   Suresh Siddha   x86, x2apic: Remo...
62
  			continue;
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
63
64
65
66
67
68
69
  
  		__x2apic_send_IPI_dest(dest, vector, apic->dest_logical);
  		/*
  		 * Cluster sibling cpus should be discared now so
  		 * we would not send IPI them second time.
  		 */
  		cpumask_andnot(ipi_mask_ptr, ipi_mask_ptr, cpus_in_cluster_ptr);
dac5f4121   Ingo Molnar   x86, apic: untang...
70
  	}
a27d0b5e7   Suresh Siddha   x86, x2apic: Remo...
71

12a67cf68   Suresh Siddha   x64, x2apic/intr-...
72
73
  	local_irq_restore(flags);
  }
a27d0b5e7   Suresh Siddha   x86, x2apic: Remo...
74
75
76
77
  static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
  {
  	__x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLINC);
  }
dac5f4121   Ingo Molnar   x86, apic: untang...
78
79
  static void
   x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
80
  {
a27d0b5e7   Suresh Siddha   x86, x2apic: Remo...
81
  	__x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);
e7986739a   Mike Travis   x86 smp: modify s...
82
  }
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
83

e7986739a   Mike Travis   x86 smp: modify s...
84
85
  static void x2apic_send_IPI_allbutself(int vector)
  {
a27d0b5e7   Suresh Siddha   x86, x2apic: Remo...
86
  	__x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLBUT);
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
87
88
89
90
  }
  
  static void x2apic_send_IPI_all(int vector)
  {
a27d0b5e7   Suresh Siddha   x86, x2apic: Remo...
91
  	__x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
92
  }
bcda016ed   Mike Travis   x86: cosmetic cha...
93
  static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask)
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
94
  {
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
95
  	/*
7d87d5365   Suresh Siddha   x86: use logical ...
96
  	 * We're using fixed IRQ delivery, can only return one logical APIC ID.
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
97
98
  	 * May as well be the first.
  	 */
debccb3e7   Ingo Molnar   x86, apic: refact...
99
  	int cpu = cpumask_first(cpumask);
e7986739a   Mike Travis   x86 smp: modify s...
100
  	if ((unsigned)cpu < nr_cpu_ids)
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
101
102
103
104
  		return per_cpu(x86_cpu_to_logical_apicid, cpu);
  	else
  		return BAD_APICID;
  }
debccb3e7   Ingo Molnar   x86, apic: refact...
105
106
107
  static unsigned int
  x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
  			      const struct cpumask *andmask)
95d313cf1   Mike Travis   x86: Add cpu_mask...
108
109
110
111
  {
  	int cpu;
  
  	/*
7d87d5365   Suresh Siddha   x86: use logical ...
112
  	 * We're using fixed IRQ delivery, can only return one logical APIC ID.
95d313cf1   Mike Travis   x86: Add cpu_mask...
113
114
  	 * May as well be the first.
  	 */
debccb3e7   Ingo Molnar   x86, apic: refact...
115
  	for_each_cpu_and(cpu, cpumask, andmask) {
a775a38b1   Mike Travis   x86: fix cpu_mask...
116
117
  		if (cpumask_test_cpu(cpu, cpu_online_mask))
  			break;
debccb3e7   Ingo Molnar   x86, apic: refact...
118
  	}
18374d89e   Suresh Siddha   x86, irq: Allow 0...
119
  	return per_cpu(x86_cpu_to_logical_apicid, cpu);
95d313cf1   Mike Travis   x86: Add cpu_mask...
120
  }
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
121
122
  static void init_x2apic_ldr(void)
  {
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  	unsigned int this_cpu = smp_processor_id();
  	unsigned int cpu;
  
  	per_cpu(x86_cpu_to_logical_apicid, this_cpu) = apic_read(APIC_LDR);
  
  	__cpu_set(this_cpu, per_cpu(cpus_in_cluster, this_cpu));
  	for_each_online_cpu(cpu) {
  		if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
  			continue;
  		__cpu_set(this_cpu, per_cpu(cpus_in_cluster, cpu));
  		__cpu_set(cpu, per_cpu(cpus_in_cluster, this_cpu));
  	}
  }
  
   /*
    * At CPU state changes, update the x2apic cluster sibling info.
    */
  static int __cpuinit
  update_clusterinfo(struct notifier_block *nfb, unsigned long action, void *hcpu)
  {
  	unsigned int this_cpu = (unsigned long)hcpu;
  	unsigned int cpu;
  	int err = 0;
  
  	switch (action) {
  	case CPU_UP_PREPARE:
  		if (!zalloc_cpumask_var(&per_cpu(cpus_in_cluster, this_cpu),
  					GFP_KERNEL)) {
  			err = -ENOMEM;
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
152
153
154
155
  		} else if (!zalloc_cpumask_var(&per_cpu(ipi_mask, this_cpu),
  					       GFP_KERNEL)) {
  			free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
  			err = -ENOMEM;
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
156
157
158
159
160
161
162
163
164
165
166
167
  		}
  		break;
  	case CPU_UP_CANCELED:
  	case CPU_UP_CANCELED_FROZEN:
  	case CPU_DEAD:
  		for_each_online_cpu(cpu) {
  			if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
  				continue;
  			__cpu_clear(this_cpu, per_cpu(cpus_in_cluster, cpu));
  			__cpu_clear(cpu, per_cpu(cpus_in_cluster, this_cpu));
  		}
  		free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
168
  		free_cpumask_var(per_cpu(ipi_mask, this_cpu));
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
169
170
171
172
173
174
175
176
177
178
179
180
  		break;
  	}
  
  	return notifier_from_errno(err);
  }
  
  static struct notifier_block __refdata x2apic_cpu_notifier = {
  	.notifier_call = update_clusterinfo,
  };
  
  static int x2apic_init_cpu_notifier(void)
  {
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
181
  	int cpu = smp_processor_id();
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
182
  	zalloc_cpumask_var(&per_cpu(cpus_in_cluster, cpu), GFP_KERNEL);
9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
183
  	zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL);
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
184

9d0fa6c5f   Cyrill Gorcunov   x86, x2apic: Mini...
185
  	BUG_ON(!per_cpu(cpus_in_cluster, cpu) || !per_cpu(ipi_mask, cpu));
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
186
187
188
189
  
  	__cpu_set(cpu, per_cpu(cpus_in_cluster, cpu));
  	register_hotcpu_notifier(&x2apic_cpu_notifier);
  	return 1;
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
190
  }
9ebd680bd   Suresh Siddha   x86, apic: Use pr...
191
192
  static int x2apic_cluster_probe(void)
  {
a39d1f3f6   Cyrill Gorcunov   x86, x2apic: Trac...
193
194
195
196
  	if (x2apic_mode)
  		return x2apic_init_cpu_notifier();
  	else
  		return 0;
9ebd680bd   Suresh Siddha   x86, apic: Use pr...
197
  }
1a8880a14   Suresh Siddha   x86, apic: Make a...
198
  static struct apic apic_x2apic_cluster = {
504a3c3ad   Ingo Molnar   x86: clean up api...
199
200
  
  	.name				= "cluster x2apic",
9ebd680bd   Suresh Siddha   x86, apic: Use pr...
201
  	.probe				= x2apic_cluster_probe,
504a3c3ad   Ingo Molnar   x86: clean up api...
202
203
  	.acpi_madt_oem_check		= x2apic_acpi_madt_oem_check,
  	.apic_id_registered		= x2apic_apic_id_registered,
f8987a109   Ingo Molnar   x86, genapic: ren...
204
  	.irq_delivery_mode		= dest_LowestPrio,
0b06e734b   Ingo Molnar   x86: clean up the...
205
  	.irq_dest_mode			= 1, /* logical */
504a3c3ad   Ingo Molnar   x86: clean up api...
206
207
  
  	.target_cpus			= x2apic_target_cpus,
08125d3ed   Ingo Molnar   x86: rename ->ESR...
208
  	.disable_esr			= 0,
bdb1a9b62   Ingo Molnar   x86, apic: rename...
209
  	.dest_logical			= APIC_DEST_LOGICAL,
504a3c3ad   Ingo Molnar   x86: clean up api...
210
211
  	.check_apicid_used		= NULL,
  	.check_apicid_present		= NULL,
504a3c3ad   Ingo Molnar   x86: clean up api...
212
213
214
215
216
217
  	.vector_allocation_domain	= x2apic_vector_allocation_domain,
  	.init_apic_ldr			= init_x2apic_ldr,
  
  	.ioapic_phys_id_map		= NULL,
  	.setup_apic_routing		= NULL,
  	.multi_timer_check		= NULL,
a21769a44   Ingo Molnar   x86, apic: clean ...
218
  	.cpu_present_to_apicid		= default_cpu_present_to_apicid,
504a3c3ad   Ingo Molnar   x86: clean up api...
219
220
  	.apicid_to_cpu_present		= NULL,
  	.setup_portio_remap		= NULL,
a27a62100   Ingo Molnar   x86: refactor ->c...
221
  	.check_phys_apicid_present	= default_check_phys_apicid_present,
504a3c3ad   Ingo Molnar   x86: clean up api...
222
  	.enable_apic_mode		= NULL,
79deb8e51   Cyrill Gorcunov   x86, x2apic: Move...
223
  	.phys_pkg_id			= x2apic_phys_pkg_id,
504a3c3ad   Ingo Molnar   x86: clean up api...
224
  	.mps_oem_check			= NULL,
79deb8e51   Cyrill Gorcunov   x86, x2apic: Move...
225
226
  	.get_apic_id			= x2apic_get_apic_id,
  	.set_apic_id			= x2apic_set_apic_id,
504a3c3ad   Ingo Molnar   x86: clean up api...
227
228
229
230
231
232
233
234
235
236
  	.apic_id_mask			= 0xFFFFFFFFu,
  
  	.cpu_mask_to_apicid		= x2apic_cpu_mask_to_apicid,
  	.cpu_mask_to_apicid_and		= x2apic_cpu_mask_to_apicid_and,
  
  	.send_IPI_mask			= x2apic_send_IPI_mask,
  	.send_IPI_mask_allbutself	= x2apic_send_IPI_mask_allbutself,
  	.send_IPI_allbutself		= x2apic_send_IPI_allbutself,
  	.send_IPI_all			= x2apic_send_IPI_all,
  	.send_IPI_self			= x2apic_send_IPI_self,
abfa584c8   Ingo Molnar   x86: set ->trampo...
237
238
  	.trampoline_phys_low		= DEFAULT_TRAMPOLINE_PHYS_LOW,
  	.trampoline_phys_high		= DEFAULT_TRAMPOLINE_PHYS_HIGH,
504a3c3ad   Ingo Molnar   x86: clean up api...
239
240
  	.wait_for_init_deassert		= NULL,
  	.smp_callin_clear_local_apic	= NULL,
504a3c3ad   Ingo Molnar   x86: clean up api...
241
  	.inquire_remote_apic		= NULL,
c1eeb2de4   Yinghai Lu   x86: fold apic_op...
242
243
244
245
246
247
248
  
  	.read				= native_apic_msr_read,
  	.write				= native_apic_msr_write,
  	.icr_read			= native_x2apic_icr_read,
  	.icr_write			= native_x2apic_icr_write,
  	.wait_icr_idle			= native_x2apic_wait_icr_idle,
  	.safe_wait_icr_idle		= native_safe_x2apic_wait_icr_idle,
12a67cf68   Suresh Siddha   x64, x2apic/intr-...
249
  };
107e0e0cd   Suresh Siddha   x86, apic: Introd...
250
251
  
  apic_driver(apic_x2apic_cluster);