Skip to content

Commit cefad86

Browse files
dwmw2KAGA-KOKO
authored andcommitted
x86/apic/x2apic: Allow CPU cluster_mask to be populated in parallel
Each of the sibling CPUs in a cluster uses the same clustermask. The first CPU in a cluster will need a new clustermask allocated, while subsequent siblings will use the same clustermask as the first. However, the CPU being brought up cannot yet perform memory allocations at the point that this occurs in init_x2apic_ldr(). So at present, the alloc_clustermask() function allocates a clustermask just in case it's needed, storing it in the global cluster_hotplug_mask. A CPU which is the first sibling of a cluster will "take" it from there and set cluster_hotplug_mask to NULL, in order for alloc_clustermask() to allocate a new one before bringing up the next CPU. To facilitate parallel bringup of CPUs in future, switch to a model where alloc_clustermask() prepopulates the clustermask in the per_cpu data for each present CPU in the cluster in advance. All that the CPU needs to do for itself in init_x2apic_ldr() is set its own bit in that mask. The 'node' and 'clusterid' members of struct cluster_mask are thus redundant, and it can become a simple struct cpumask instead. Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: David Woodhouse <[email protected]> Signed-off-by: Usama Arif <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Paul E. McKenney <[email protected]> Tested-by: Kim Phillips <[email protected]> Tested-by: Oleksandr Natalenko <[email protected]> Tested-by: Guilherme G. Piccoli <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent e8d018d commit cefad86

File tree

1 file changed

+82
-44
lines changed

1 file changed

+82
-44
lines changed

arch/x86/kernel/apic/x2apic_cluster.c

Lines changed: 82 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@
99

1010
#include "local.h"
1111

12-
struct cluster_mask {
13-
unsigned int clusterid;
14-
int node;
15-
struct cpumask mask;
16-
};
12+
#define apic_cluster(apicid) ((apicid) >> 4)
1713

1814
/*
1915
* __x2apic_send_IPI_mask() possibly needs to read
@@ -23,8 +19,7 @@ struct cluster_mask {
2319
static u32 *x86_cpu_to_logical_apicid __read_mostly;
2420

2521
static DEFINE_PER_CPU(cpumask_var_t, ipi_mask);
26-
static DEFINE_PER_CPU_READ_MOSTLY(struct cluster_mask *, cluster_masks);
27-
static struct cluster_mask *cluster_hotplug_mask;
22+
static DEFINE_PER_CPU_READ_MOSTLY(struct cpumask *, cluster_masks);
2823

2924
static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
3025
{
@@ -60,18 +55,18 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
6055

6156
/* Collapse cpus in a cluster so a single IPI per cluster is sent */
6257
for_each_cpu(cpu, tmpmsk) {
63-
struct cluster_mask *cmsk = per_cpu(cluster_masks, cpu);
58+
struct cpumask *cmsk = per_cpu(cluster_masks, cpu);
6459

6560
dest = 0;
66-
for_each_cpu_and(clustercpu, tmpmsk, &cmsk->mask)
61+
for_each_cpu_and(clustercpu, tmpmsk, cmsk)
6762
dest |= x86_cpu_to_logical_apicid[clustercpu];
6863

6964
if (!dest)
7065
continue;
7166

7267
__x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
7368
/* Remove cluster CPUs from tmpmask */
74-
cpumask_andnot(tmpmsk, tmpmsk, &cmsk->mask);
69+
cpumask_andnot(tmpmsk, tmpmsk, cmsk);
7570
}
7671

7772
local_irq_restore(flags);
@@ -105,55 +100,98 @@ static u32 x2apic_calc_apicid(unsigned int cpu)
105100

106101
static void init_x2apic_ldr(void)
107102
{
108-
struct cluster_mask *cmsk = this_cpu_read(cluster_masks);
109-
u32 cluster, apicid = apic_read(APIC_LDR);
110-
unsigned int cpu;
103+
struct cpumask *cmsk = this_cpu_read(cluster_masks);
111104

112-
x86_cpu_to_logical_apicid[smp_processor_id()] = apicid;
105+
BUG_ON(!cmsk);
113106

114-
if (cmsk)
115-
goto update;
116-
117-
cluster = apicid >> 16;
118-
for_each_online_cpu(cpu) {
119-
cmsk = per_cpu(cluster_masks, cpu);
120-
/* Matching cluster found. Link and update it. */
121-
if (cmsk && cmsk->clusterid == cluster)
122-
goto update;
107+
cpumask_set_cpu(smp_processor_id(), cmsk);
108+
}
109+
110+
/*
111+
* As an optimisation during boot, set the cluster_mask for all present
112+
* CPUs at once, to prevent each of them having to iterate over the others
113+
* to find the existing cluster_mask.
114+
*/
115+
static void prefill_clustermask(struct cpumask *cmsk, unsigned int cpu, u32 cluster)
116+
{
117+
int cpu_i;
118+
119+
for_each_present_cpu(cpu_i) {
120+
struct cpumask **cpu_cmsk = &per_cpu(cluster_masks, cpu_i);
121+
u32 apicid = apic->cpu_present_to_apicid(cpu_i);
122+
123+
if (apicid == BAD_APICID || cpu_i == cpu || apic_cluster(apicid) != cluster)
124+
continue;
125+
126+
if (WARN_ON_ONCE(*cpu_cmsk == cmsk))
127+
continue;
128+
129+
BUG_ON(*cpu_cmsk);
130+
*cpu_cmsk = cmsk;
123131
}
124-
cmsk = cluster_hotplug_mask;
125-
cmsk->clusterid = cluster;
126-
cluster_hotplug_mask = NULL;
127-
update:
128-
this_cpu_write(cluster_masks, cmsk);
129-
cpumask_set_cpu(smp_processor_id(), &cmsk->mask);
130132
}
131133

132-
static int alloc_clustermask(unsigned int cpu, int node)
134+
static int alloc_clustermask(unsigned int cpu, u32 cluster, int node)
133135
{
136+
struct cpumask *cmsk = NULL;
137+
unsigned int cpu_i;
138+
139+
/*
140+
* At boot time, the CPU present mask is stable. The cluster mask is
141+
* allocated for the first CPU in the cluster and propagated to all
142+
* present siblings in the cluster. If the cluster mask is already set
143+
* on entry to this function for a given CPU, there is nothing to do.
144+
*/
134145
if (per_cpu(cluster_masks, cpu))
135146
return 0;
147+
148+
if (system_state < SYSTEM_RUNNING)
149+
goto alloc;
150+
136151
/*
137-
* If a hotplug spare mask exists, check whether it's on the right
138-
* node. If not, free it and allocate a new one.
152+
* On post boot hotplug for a CPU which was not present at boot time,
153+
* iterate over all possible CPUs (even those which are not present
154+
* any more) to find any existing cluster mask.
139155
*/
140-
if (cluster_hotplug_mask) {
141-
if (cluster_hotplug_mask->node == node)
142-
return 0;
143-
kfree(cluster_hotplug_mask);
156+
for_each_possible_cpu(cpu_i) {
157+
u32 apicid = apic->cpu_present_to_apicid(cpu_i);
158+
159+
if (apicid != BAD_APICID && apic_cluster(apicid) == cluster) {
160+
cmsk = per_cpu(cluster_masks, cpu_i);
161+
/*
162+
* If the cluster is already initialized, just store
163+
* the mask and return. There's no need to propagate.
164+
*/
165+
if (cmsk) {
166+
per_cpu(cluster_masks, cpu) = cmsk;
167+
return 0;
168+
}
169+
}
144170
}
145-
146-
cluster_hotplug_mask = kzalloc_node(sizeof(*cluster_hotplug_mask),
147-
GFP_KERNEL, node);
148-
if (!cluster_hotplug_mask)
171+
/*
172+
* No CPU in the cluster has ever been initialized, so fall through to
173+
* the boot time code which will also populate the cluster mask for any
174+
* other CPU in the cluster which is (now) present.
175+
*/
176+
alloc:
177+
cmsk = kzalloc_node(sizeof(*cmsk), GFP_KERNEL, node);
178+
if (!cmsk)
149179
return -ENOMEM;
150-
cluster_hotplug_mask->node = node;
180+
per_cpu(cluster_masks, cpu) = cmsk;
181+
prefill_clustermask(cmsk, cpu, cluster);
182+
151183
return 0;
152184
}
153185

154186
static int x2apic_prepare_cpu(unsigned int cpu)
155187
{
156-
if (alloc_clustermask(cpu, cpu_to_node(cpu)) < 0)
188+
u32 phys_apicid = apic->cpu_present_to_apicid(cpu);
189+
u32 cluster = apic_cluster(phys_apicid);
190+
u32 logical_apicid = (cluster << 16) | (1 << (phys_apicid & 0xf));
191+
192+
x86_cpu_to_logical_apicid[cpu] = logical_apicid;
193+
194+
if (alloc_clustermask(cpu, cluster, cpu_to_node(cpu)) < 0)
157195
return -ENOMEM;
158196
if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL))
159197
return -ENOMEM;
@@ -162,10 +200,10 @@ static int x2apic_prepare_cpu(unsigned int cpu)
162200

163201
static int x2apic_dead_cpu(unsigned int dead_cpu)
164202
{
165-
struct cluster_mask *cmsk = per_cpu(cluster_masks, dead_cpu);
203+
struct cpumask *cmsk = per_cpu(cluster_masks, dead_cpu);
166204

167205
if (cmsk)
168-
cpumask_clear_cpu(dead_cpu, &cmsk->mask);
206+
cpumask_clear_cpu(dead_cpu, cmsk);
169207
free_cpumask_var(per_cpu(ipi_mask, dead_cpu));
170208
return 0;
171209
}

0 commit comments

Comments
 (0)