Skip to content

Commit cccf34e

Browse files
Markos Chandrasralfbaechle
authored andcommitted
MIPS: c-r4k: Fix cache flushing for MT cores
MT_SMP is not the only SMP option for MT cores. The MT_SMP option allows more than one VPE per core to appear as a secondary CPU in the system. Because of how CM works, it propagates the address-based cache ops to the secondary cores but not the index-based ones. Because of that, the code does not use IPIs to flush the L1 caches on secondary cores because the CM would have done that already. However, the CM functionality is independent of the type of SMP kernel so even in non-MT kernels, IPIs are not necessary. As a result of which, we change the conditional to depend on the CM presence. Moreover, since VPEs on the same core share the same L1 caches, there is no need to send an IPI on all of them so we calculate a suitable cpumask with only one VPE per core. Signed-off-by: Markos Chandras <markos.chandras@imgtec.com> Cc: <stable@vger.kernel.org> # 3.15+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10654/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
1 parent 1c88535 commit cccf34e

File tree

3 files changed

+55
-4
lines changed

3 files changed

+55
-4
lines changed

arch/mips/include/asm/smp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
extern int smp_num_siblings;
2424
extern cpumask_t cpu_sibling_map[];
2525
extern cpumask_t cpu_core_map[];
26+
extern cpumask_t cpu_foreign_map;
2627

2728
#define raw_smp_processor_id() (current_thread_info()->cpu)
2829

arch/mips/kernel/smp.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ EXPORT_SYMBOL(cpu_sibling_map);
6363
cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
6464
EXPORT_SYMBOL(cpu_core_map);
6565

66+
/*
67+
* A logcal cpu mask containing only one VPE per core to
68+
* reduce the number of IPIs on large MT systems.
69+
*/
70+
cpumask_t cpu_foreign_map __read_mostly;
71+
EXPORT_SYMBOL(cpu_foreign_map);
72+
6673
/* representing cpus for which sibling maps can be computed */
6774
static cpumask_t cpu_sibling_setup_map;
6875

@@ -103,6 +110,29 @@ static inline void set_cpu_core_map(int cpu)
103110
}
104111
}
105112

113+
/*
114+
* Calculate a new cpu_foreign_map mask whenever a
115+
* new cpu appears or disappears.
116+
*/
117+
static inline void calculate_cpu_foreign_map(void)
118+
{
119+
int i, k, core_present;
120+
cpumask_t temp_foreign_map;
121+
122+
/* Re-calculate the mask */
123+
for_each_online_cpu(i) {
124+
core_present = 0;
125+
for_each_cpu(k, &temp_foreign_map)
126+
if (cpu_data[i].package == cpu_data[k].package &&
127+
cpu_data[i].core == cpu_data[k].core)
128+
core_present = 1;
129+
if (!core_present)
130+
cpumask_set_cpu(i, &temp_foreign_map);
131+
}
132+
133+
cpumask_copy(&cpu_foreign_map, &temp_foreign_map);
134+
}
135+
106136
struct plat_smp_ops *mp_ops;
107137
EXPORT_SYMBOL(mp_ops);
108138

@@ -146,6 +176,8 @@ asmlinkage void start_secondary(void)
146176
set_cpu_sibling_map(cpu);
147177
set_cpu_core_map(cpu);
148178

179+
calculate_cpu_foreign_map();
180+
149181
cpumask_set_cpu(cpu, &cpu_callin_map);
150182

151183
synchronise_count_slave(cpu);
@@ -173,9 +205,18 @@ void __irq_entry smp_call_function_interrupt(void)
173205
static void stop_this_cpu(void *dummy)
174206
{
175207
/*
176-
* Remove this CPU:
208+
* Remove this CPU. Be a bit slow here and
209+
* set the bits for every online CPU so we don't miss
210+
* any IPI whilst taking this VPE down.
177211
*/
212+
213+
cpumask_copy(&cpu_foreign_map, cpu_online_mask);
214+
215+
/* Make it visible to every other CPU */
216+
smp_mb();
217+
178218
set_cpu_online(smp_processor_id(), false);
219+
calculate_cpu_foreign_map();
179220
local_irq_disable();
180221
while (1);
181222
}
@@ -197,6 +238,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
197238
mp_ops->prepare_cpus(max_cpus);
198239
set_cpu_sibling_map(0);
199240
set_cpu_core_map(0);
241+
calculate_cpu_foreign_map();
200242
#ifndef CONFIG_HOTPLUG_CPU
201243
init_cpu_present(cpu_possible_mask);
202244
#endif

arch/mips/mm/c-r4k.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <asm/cacheflush.h> /* for run_uncached() */
3838
#include <asm/traps.h>
3939
#include <asm/dma-coherence.h>
40+
#include <asm/mips-cm.h>
4041

4142
/*
4243
* Special Variant of smp_call_function for use by cache functions:
@@ -51,9 +52,16 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
5152
{
5253
preempt_disable();
5354

54-
#ifndef CONFIG_MIPS_MT_SMP
55-
smp_call_function(func, info, 1);
56-
#endif
55+
/*
56+
* The Coherent Manager propagates address-based cache ops to other
57+
* cores but not index-based ops. However, r4k_on_each_cpu is used
58+
* in both cases so there is no easy way to tell what kind of op is
59+
* executed to the other cores. The best we can probably do is
60+
* to restrict that call when a CM is not present because both
61+
* CM-based SMP protocols (CMP & CPS) restrict index-based cache ops.
62+
*/
63+
if (!mips_cm_present())
64+
smp_call_function_many(&cpu_foreign_map, func, info, 1);
5765
func(info);
5866
preempt_enable();
5967
}

0 commit comments

Comments
 (0)