summaryrefslogtreecommitdiffstats
path: root/arch/arc/kernel
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-11-26 10:53:44 +0100
committerVineet Gupta <vgupta@synopsys.com>2013-12-23 07:35:04 +0100
commitf2a4aa5646687f9a51616581221b1d348590d47e (patch)
tree19845c1811e71f6b2ee3d4837b3b1a8caeb47be3 /arch/arc/kernel
parentARC: [SMP] cpu halt interface doesn't need "self" cpu-id (diff)
downloadlinux-f2a4aa5646687f9a51616581221b1d348590d47e.tar.xz
linux-f2a4aa5646687f9a51616581221b1d348590d47e.zip
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/kernel')
-rw-r--r--arch/arc/kernel/smp.c56
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;
}