Skip to content

Commit

Permalink
[ARM] smp: fix cpumask usage in ARM SMP code
Browse files Browse the repository at this point in the history
The ARM SMP code wasn't properly updated for the cpumask changes, which
results in smp_timer_broadcast() broadcasting ticks to non-online CPUs.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King authored and Russell King committed May 17, 2009
1 parent 0f6f49a commit 8266810
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 46 deletions.
4 changes: 2 additions & 2 deletions arch/arm/common/gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,9 @@ void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
}

#ifdef CONFIG_SMP
void gic_raise_softirq(cpumask_t cpumask, unsigned int irq)
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
unsigned long map = *cpus_addr(cpumask);
unsigned long map = *cpus_addr(*mask);

/* this always happens on GIC0 */
writel(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/include/asm/hardware/gic.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
void gic_dist_init(unsigned int gic_nr, void __iomem *base, unsigned int irq_start);
void gic_cpu_init(unsigned int gic_nr, void __iomem *base);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_raise_softirq(cpumask_t cpumask, unsigned int irq);
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
#endif

#endif
12 changes: 4 additions & 8 deletions arch/arm/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,12 @@ extern void smp_store_cpu_info(unsigned int cpuid);
/*
* Raise an IPI cross call on CPUs in callmap.
*/
extern void smp_cross_call(cpumask_t callmap);

/*
* Broadcast a timer interrupt to the other CPUs.
*/
extern void smp_send_timer(void);
extern void smp_cross_call(const struct cpumask *mask);

/*
* Broadcast a clock event to other CPUs.
*/
extern void smp_timer_broadcast(cpumask_t mask);
extern void smp_timer_broadcast(const struct cpumask *mask);

/*
* Boot a secondary CPU, and assign it the specified idle task.
Expand Down Expand Up @@ -102,7 +97,8 @@ extern int platform_cpu_kill(unsigned int cpu);
extern void platform_cpu_enable(unsigned int cpu);

extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi(cpumask_t mask);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask

/*
* Local timer interrupt handling function (can be IPI'ed).
Expand Down
46 changes: 16 additions & 30 deletions arch/arm/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,14 +326,14 @@ void __init smp_prepare_boot_cpu(void)
per_cpu(cpu_data, cpu).idle = current;
}

static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg)
static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg)
{
unsigned long flags;
unsigned int cpu;

local_irq_save(flags);

for_each_cpu_mask(cpu, callmap) {
for_each_cpu(cpu, mask) {
struct ipi_data *ipi = &per_cpu(ipi_data, cpu);

spin_lock(&ipi->lock);
Expand All @@ -344,19 +344,19 @@ static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg)
/*
* Call the platform specific cross-CPU call function.
*/
smp_cross_call(callmap);
smp_cross_call(mask);

local_irq_restore(flags);
}

void arch_send_call_function_ipi(cpumask_t mask)
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
send_ipi_message(mask, IPI_CALL_FUNC);
}

void arch_send_call_function_single_ipi(int cpu)
{
send_ipi_message(cpumask_of_cpu(cpu), IPI_CALL_FUNC_SINGLE);
send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
}

void show_ipi_list(struct seq_file *p)
Expand Down Expand Up @@ -498,17 +498,10 @@ asmlinkage void __exception do_IPI(struct pt_regs *regs)

void smp_send_reschedule(int cpu)
{
send_ipi_message(cpumask_of_cpu(cpu), IPI_RESCHEDULE);
send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
}

void smp_send_timer(void)
{
cpumask_t mask = cpu_online_map;
cpu_clear(smp_processor_id(), mask);
send_ipi_message(mask, IPI_TIMER);
}

void smp_timer_broadcast(cpumask_t mask)
void smp_timer_broadcast(const struct cpumask *mask)
{
send_ipi_message(mask, IPI_TIMER);
}
Expand All @@ -517,7 +510,7 @@ void smp_send_stop(void)
{
cpumask_t mask = cpu_online_map;
cpu_clear(smp_processor_id(), mask);
send_ipi_message(mask, IPI_CPU_STOP);
send_ipi_message(&mask, IPI_CPU_STOP);
}

/*
Expand All @@ -528,20 +521,17 @@ int setup_profiling_timer(unsigned int multiplier)
return -EINVAL;
}

static int
on_each_cpu_mask(void (*func)(void *), void *info, int wait, cpumask_t mask)
static void
on_each_cpu_mask(void (*func)(void *), void *info, int wait,
const struct cpumask *mask)
{
int ret = 0;

preempt_disable();

ret = smp_call_function_mask(mask, func, info, wait);
if (cpu_isset(smp_processor_id(), mask))
smp_call_function_many(mask, func, info, wait);
if (cpumask_test_cpu(smp_processor_id(), mask))
func(info);

preempt_enable();

return ret;
}

/**********************************************************************/
Expand Down Expand Up @@ -602,20 +592,17 @@ void flush_tlb_all(void)

void flush_tlb_mm(struct mm_struct *mm)
{
cpumask_t mask = mm->cpu_vm_mask;

on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mask);
on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask);
}

void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
{
cpumask_t mask = vma->vm_mm->cpu_vm_mask;
struct tlb_args ta;

ta.ta_vma = vma;
ta.ta_start = uaddr;

on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mask);
on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask);
}

void flush_tlb_kernel_page(unsigned long kaddr)
Expand All @@ -630,14 +617,13 @@ void flush_tlb_kernel_page(unsigned long kaddr)
void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
cpumask_t mask = vma->vm_mm->cpu_vm_mask;
struct tlb_args ta;

ta.ta_vma = vma;
ta.ta_start = start;
ta.ta_end = end;

on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mask);
on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask);
}

void flush_tlb_kernel_range(unsigned long start, unsigned long end)
Expand Down
6 changes: 3 additions & 3 deletions arch/arm/mach-realview/include/mach/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
/*
* We use IRQ1 as the IPI
*/
static inline void smp_cross_call(cpumask_t callmap)
static inline void smp_cross_call(const struct cpumask *mask)
{
gic_raise_softirq(callmap, 1);
gic_raise_softirq(mask, 1);
}

/*
* Do nothing on MPcore.
*/
static inline void smp_cross_call_done(cpumask_t callmap)
static inline void smp_cross_call_done(const struct cpumask *mask)
{
}

Expand Down
4 changes: 2 additions & 2 deletions arch/arm/mach-realview/platsmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
* to get this processor out of WFI in the BootMonitor - make
* sure that we are no longer being sent this soft interrupt
*/
smp_cross_call_done(cpumask_of_cpu(cpu));
smp_cross_call_done(cpumask_of(cpu));

/*
* if any interrupts are already enabled for the primary
Expand Down Expand Up @@ -136,7 +136,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
* Use smp_cross_call() for this, since there's little
* point duplicating the code here
*/
smp_cross_call(cpumask_of_cpu(cpu));
smp_cross_call(cpumask_of(cpu));

timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
Expand Down

0 comments on commit 8266810

Please sign in to comment.