diff options
author | Vineet Gupta <vgupta@synopsys.com> | 2013-11-26 13:53:44 +0400 |
---|---|---|
committer | Vineet Gupta <vgupta@synopsys.com> | 2013-12-23 10:35:04 +0400 |
commit | f2a4aa5646687f9a51616581221b1d348590d47e (patch) | |
tree | 19845c1811e71f6b2ee3d4837b3b1a8caeb47be3 /arch/arc | |
parent | 53dc110c97436dcf2a758091c98093657116e91c (diff) | |
download | linux-f2a4aa5646687f9a51616581221b1d348590d47e.tar.xz |
ARC: [SMP] simplify IPI code
* ipi_data is just a word, no need to keep it as struct
* find_next_bit() not needed to loop thru a 32bit word, ffs suffices
Diffstat (limited to 'arch/arc')
-rw-r--r-- | arch/arc/kernel/smp.c | 56 |
1 files changed, 28 insertions, 28 deletions
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 467dd9cca18f..c00c612e8dd3 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -197,37 +197,31 @@ int __init setup_profiling_timer(unsigned int multiplier) /* Inter Processor Interrupt Handling */ /*****************************************************************************/ -/* - * structures for inter-processor calls - * A Collection of single bit ipi messages - * - */ - -/* - * TODO_rajesh investigate tlb message types. - * IPI Timer not needed because each ARC has an individual Interrupting Timer - */ enum ipi_msg_type { - IPI_NOP = 0, + IPI_EMPTY = 0, IPI_RESCHEDULE = 1, IPI_CALL_FUNC, - IPI_CPU_STOP + IPI_CPU_STOP, }; -struct ipi_data { - unsigned long bits; -}; +/* + * In arches with IRQ for each msg type (above), receiver can use IRQ-id to + * figure out what msg was sent. For those which don't (ARC has dedicated IPI + * IRQ), the msg-type needs to be conveyed via per-cpu data + */ -static DEFINE_PER_CPU(struct ipi_data, ipi_data); +static DEFINE_PER_CPU(unsigned long, ipi_data); static void ipi_send_msg_one(int cpu, enum ipi_msg_type msg) { - struct ipi_data *ipi = &per_cpu(ipi_data, cpu); + unsigned long __percpu *ipi_data_ptr = per_cpu_ptr(&ipi_data, cpu); unsigned long flags; + pr_debug("%d Sending msg [%d] to %d\n", smp_processor_id(), msg, cpu); + local_irq_save(flags); - set_bit(msg, &ipi->bits); + set_bit(msg, ipi_data_ptr); /* Call the platform specific cross-CPU call function */ if (plat_smp_ops.ipi_send) @@ -275,12 +269,11 @@ static void ipi_cpu_stop(void) machine_halt(); } -static inline void __do_IPI(unsigned long *ops, struct ipi_data *ipi) +static inline void __do_IPI(unsigned long pending) { - unsigned long msg = 0; + while (pending) { - do { - msg = find_next_bit(ops, BITS_PER_LONG, msg+1); + unsigned long msg = __ffs(pending); switch (msg) { case IPI_RESCHEDULE: @@ -294,8 +287,14 @@ static inline void __do_IPI(unsigned long *ops, struct ipi_data *ipi) case IPI_CPU_STOP: ipi_cpu_stop(); break; + + default: + pr_warn("IPI missing msg\n"); + } - } while (msg < BITS_PER_LONG); + + pending &= ~(1U << msg); + } } /* @@ -304,9 +303,10 @@ static inline void __do_IPI(unsigned long *ops, struct ipi_data *ipi) */ irqreturn_t do_IPI(int irq, void *dev_id) { - int cpu = smp_processor_id(); - struct ipi_data *ipi = &per_cpu(ipi_data, cpu); - unsigned long ops; + unsigned long pending; + + pr_debug("IPI [%ld] received on cpu %d\n", + *this_cpu_ptr(&ipi_data), smp_processor_id()); if (plat_smp_ops.ipi_clear) plat_smp_ops.ipi_clear(irq); @@ -315,8 +315,8 @@ irqreturn_t do_IPI(int irq, void *dev_id) * XXX: is this loop really needed * And do we need to move ipi_clean inside */ - while ((ops = xchg(&ipi->bits, 0)) != 0) - __do_IPI(&ops, ipi); + while ((pending = xchg(this_cpu_ptr(&ipi_data), 0)) != 0) + __do_IPI(pending); return IRQ_HANDLED; } |