Skip to content

Commit 023a611

Browse files
committedSep 25, 2017
x86/apic/x2apic: Simplify cluster management
The cluster management code creates a cluster mask per cpu, which requires that on cpu on/offline all cluster masks have to be iterated and updated. Other information about the cluster is in different per cpu variables. Create a data structure which holds all information about a cluster and fill it in when the first CPU of a cluster comes online. If another CPU of a cluster comes online it just finds the pointer to the existing cluster structure and reuses it. That simplifies all usage sites and gets rid of quite some pointless iterations over the online cpus to find the cpus which belong to the cluster. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Juergen Gross <jgross@suse.com> Tested-by: Yu Chen <yu.c.chen@intel.com> Acked-by: Juergen Gross <jgross@suse.com> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Marc Zyngier <marc.zyngier@arm.com> Cc: Alok Kataria <akataria@vmware.com> Cc: Joerg Roedel <joro@8bytes.org> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Christoph Hellwig <hch@lst.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Rui Zhang <rui.zhang@intel.com> Cc: "K. Y. Srinivasan" <kys@microsoft.com> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Len Brown <lenb@kernel.org> Link: https://lkml.kernel.org/r/20170913213153.992629420@linutronix.de
1 parent 72f48a3 commit 023a611

File tree

1 file changed

+75
-77
lines changed

1 file changed

+75
-77
lines changed
 

‎arch/x86/kernel/apic/x2apic_cluster.c

+75-77
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@
1010
#include <asm/smp.h>
1111
#include "x2apic.h"
1212

13+
struct cluster_mask {
14+
unsigned int clusterid;
15+
int node;
16+
struct cpumask mask;
17+
};
18+
1319
static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
14-
static DEFINE_PER_CPU(cpumask_var_t, cpus_in_cluster);
1520
static DEFINE_PER_CPU(cpumask_var_t, ipi_mask);
21+
static DEFINE_PER_CPU(struct cluster_mask *, cluster_masks);
22+
static struct cluster_mask *cluster_hotplug_mask;
1623

1724
static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
1825
{
1926
return x2apic_enabled();
2027
}
2128

22-
static inline u32 x2apic_cluster(int cpu)
23-
{
24-
return per_cpu(x86_cpu_to_logical_apicid, cpu) >> 16;
25-
}
26-
2729
static void x2apic_send_IPI(int cpu, int vector)
2830
{
2931
u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
@@ -35,49 +37,34 @@ static void x2apic_send_IPI(int cpu, int vector)
3537
static void
3638
__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
3739
{
38-
struct cpumask *cpus_in_cluster_ptr;
39-
struct cpumask *ipi_mask_ptr;
40-
unsigned int cpu, this_cpu;
40+
unsigned int cpu, clustercpu;
41+
struct cpumask *tmpmsk;
4142
unsigned long flags;
4243
u32 dest;
4344

4445
x2apic_wrmsr_fence();
45-
4646
local_irq_save(flags);
4747

48-
this_cpu = smp_processor_id();
48+
tmpmsk = this_cpu_cpumask_var_ptr(ipi_mask);
49+
cpumask_copy(tmpmsk, mask);
50+
/* If IPI should not be sent to self, clear current CPU */
51+
if (apic_dest != APIC_DEST_ALLINC)
52+
cpumask_clear_cpu(smp_processor_id(), tmpmsk);
4953

50-
/*
51-
* We are to modify mask, so we need an own copy
52-
* and be sure it's manipulated with irq off.
53-
*/
54-
ipi_mask_ptr = this_cpu_cpumask_var_ptr(ipi_mask);
55-
cpumask_copy(ipi_mask_ptr, mask);
54+
/* Collapse cpus in a cluster so a single IPI per cluster is sent */
55+
for_each_cpu(cpu, tmpmsk) {
56+
struct cluster_mask *cmsk = per_cpu(cluster_masks, cpu);
5657

57-
/*
58-
* The idea is to send one IPI per cluster.
59-
*/
60-
for_each_cpu(cpu, ipi_mask_ptr) {
61-
unsigned long i;
62-
63-
cpus_in_cluster_ptr = per_cpu(cpus_in_cluster, cpu);
6458
dest = 0;
65-
66-
/* Collect cpus in cluster. */
67-
for_each_cpu_and(i, ipi_mask_ptr, cpus_in_cluster_ptr) {
68-
if (apic_dest == APIC_DEST_ALLINC || i != this_cpu)
69-
dest |= per_cpu(x86_cpu_to_logical_apicid, i);
70-
}
59+
for_each_cpu_and(clustercpu, tmpmsk, &cmsk->mask)
60+
dest |= per_cpu(x86_cpu_to_logical_apicid, clustercpu);
7161

7262
if (!dest)
7363
continue;
7464

7565
__x2apic_send_IPI_dest(dest, vector, apic->dest_logical);
76-
/*
77-
* Cluster sibling cpus should be discared now so
78-
* we would not send IPI them second time.
79-
*/
80-
cpumask_andnot(ipi_mask_ptr, ipi_mask_ptr, cpus_in_cluster_ptr);
66+
/* Remove cluster CPUs from tmpmask */
67+
cpumask_andnot(tmpmsk, tmpmsk, &cmsk->mask);
8168
}
8269

8370
local_irq_restore(flags);
@@ -109,91 +96,100 @@ x2apic_cpu_mask_to_apicid(const struct cpumask *mask, struct irq_data *irqdata,
10996
unsigned int *apicid)
11097
{
11198
struct cpumask *effmsk = irq_data_get_effective_affinity_mask(irqdata);
99+
struct cluster_mask *cmsk;
112100
unsigned int cpu;
113101
u32 dest = 0;
114-
u16 cluster;
115102

116103
cpu = cpumask_first(mask);
117104
if (cpu >= nr_cpu_ids)
118105
return -EINVAL;
119106

120-
dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
121-
cluster = x2apic_cluster(cpu);
122-
107+
cmsk = per_cpu(cluster_masks, cpu);
123108
cpumask_clear(effmsk);
124-
for_each_cpu(cpu, mask) {
125-
if (cluster != x2apic_cluster(cpu))
126-
continue;
109+
for_each_cpu_and(cpu, &cmsk->mask, mask) {
127110
dest |= per_cpu(x86_cpu_to_logical_apicid, cpu);
128111
cpumask_set_cpu(cpu, effmsk);
129112
}
130-
131113
*apicid = dest;
132114
return 0;
133115
}
134116

135117
static void init_x2apic_ldr(void)
136118
{
137-
unsigned int this_cpu = smp_processor_id();
119+
struct cluster_mask *cmsk = this_cpu_read(cluster_masks);
120+
u32 cluster, apicid = apic_read(APIC_LDR);
138121
unsigned int cpu;
139122

140-
per_cpu(x86_cpu_to_logical_apicid, this_cpu) = apic_read(APIC_LDR);
123+
this_cpu_write(x86_cpu_to_logical_apicid, apicid);
141124

142-
cpumask_set_cpu(this_cpu, per_cpu(cpus_in_cluster, this_cpu));
125+
if (cmsk)
126+
goto update;
127+
128+
cluster = apicid >> 16;
143129
for_each_online_cpu(cpu) {
144-
if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
145-
continue;
146-
cpumask_set_cpu(this_cpu, per_cpu(cpus_in_cluster, cpu));
147-
cpumask_set_cpu(cpu, per_cpu(cpus_in_cluster, this_cpu));
130+
cmsk = per_cpu(cluster_masks, cpu);
131+
/* Matching cluster found. Link and update it. */
132+
if (cmsk && cmsk->clusterid == cluster)
133+
goto update;
148134
}
135+
cmsk = cluster_hotplug_mask;
136+
cluster_hotplug_mask = NULL;
137+
update:
138+
this_cpu_write(cluster_masks, cmsk);
139+
cpumask_set_cpu(smp_processor_id(), &cmsk->mask);
149140
}
150141

151-
/*
152-
* At CPU state changes, update the x2apic cluster sibling info.
153-
*/
154-
static int x2apic_prepare_cpu(unsigned int cpu)
142+
static int alloc_clustermask(unsigned int cpu, int node)
155143
{
156-
if (!zalloc_cpumask_var(&per_cpu(cpus_in_cluster, cpu), GFP_KERNEL))
157-
return -ENOMEM;
144+
if (per_cpu(cluster_masks, cpu))
145+
return 0;
146+
/*
147+
* If a hotplug spare mask exists, check whether it's on the right
148+
* node. If not, free it and allocate a new one.
149+
*/
150+
if (cluster_hotplug_mask) {
151+
if (cluster_hotplug_mask->node == node)
152+
return 0;
153+
kfree(cluster_hotplug_mask);
154+
}
158155

159-
if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL)) {
160-
free_cpumask_var(per_cpu(cpus_in_cluster, cpu));
156+
cluster_hotplug_mask = kzalloc_node(sizeof(*cluster_hotplug_mask),
157+
GFP_KERNEL, node);
158+
if (!cluster_hotplug_mask)
161159
return -ENOMEM;
162-
}
160+
cluster_hotplug_mask->node = node;
161+
return 0;
162+
}
163163

164+
static int x2apic_prepare_cpu(unsigned int cpu)
165+
{
166+
if (alloc_clustermask(cpu, cpu_to_node(cpu)) < 0)
167+
return -ENOMEM;
168+
if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL))
169+
return -ENOMEM;
164170
return 0;
165171
}
166172

167-
static int x2apic_dead_cpu(unsigned int this_cpu)
173+
static int x2apic_dead_cpu(unsigned int dead_cpu)
168174
{
169-
int cpu;
175+
struct cluster_mask *cmsk = per_cpu(cluster_masks, dead_cpu);
170176

171-
for_each_online_cpu(cpu) {
172-
if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
173-
continue;
174-
cpumask_clear_cpu(this_cpu, per_cpu(cpus_in_cluster, cpu));
175-
cpumask_clear_cpu(cpu, per_cpu(cpus_in_cluster, this_cpu));
176-
}
177-
free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
178-
free_cpumask_var(per_cpu(ipi_mask, this_cpu));
177+
cpumask_clear_cpu(smp_processor_id(), &cmsk->mask);
178+
free_cpumask_var(per_cpu(ipi_mask, dead_cpu));
179179
return 0;
180180
}
181181

182182
static int x2apic_cluster_probe(void)
183183
{
184-
int cpu = smp_processor_id();
185-
int ret;
186-
187184
if (!x2apic_mode)
188185
return 0;
189186

190-
ret = cpuhp_setup_state(CPUHP_X2APIC_PREPARE, "x86/x2apic:prepare",
191-
x2apic_prepare_cpu, x2apic_dead_cpu);
192-
if (ret < 0) {
187+
if (cpuhp_setup_state(CPUHP_X2APIC_PREPARE, "x86/x2apic:prepare",
188+
x2apic_prepare_cpu, x2apic_dead_cpu) < 0) {
193189
pr_err("Failed to register X2APIC_PREPARE\n");
194190
return 0;
195191
}
196-
cpumask_set_cpu(cpu, per_cpu(cpus_in_cluster, cpu));
192+
init_x2apic_ldr();
197193
return 1;
198194
}
199195

@@ -208,6 +204,8 @@ static const struct cpumask *x2apic_cluster_target_cpus(void)
208204
static void cluster_vector_allocation_domain(int cpu, struct cpumask *retmask,
209205
const struct cpumask *mask)
210206
{
207+
struct cluster_mask *cmsk = per_cpu(cluster_masks, cpu);
208+
211209
/*
212210
* To minimize vector pressure, default case of boot, device bringup
213211
* etc will use a single cpu for the interrupt destination.
@@ -220,7 +218,7 @@ static void cluster_vector_allocation_domain(int cpu, struct cpumask *retmask,
220218
if (mask == x2apic_cluster_target_cpus())
221219
cpumask_copy(retmask, cpumask_of(cpu));
222220
else
223-
cpumask_and(retmask, mask, per_cpu(cpus_in_cluster, cpu));
221+
cpumask_and(retmask, mask, &cmsk->mask);
224222
}
225223

226224
static struct apic apic_x2apic_cluster __ro_after_init = {

0 commit comments

Comments
 (0)
Please sign in to comment.