|
@@ -11,9 +11,13 @@
|
|
|
#include <linux/smp.h>
|
|
|
#include <linux/irq.h>
|
|
|
#include <linux/spinlock.h>
|
|
|
+#include <asm/irqflags-arcv2.h>
|
|
|
#include <asm/mcip.h>
|
|
|
#include <asm/setup.h>
|
|
|
|
|
|
+#define IPI_IRQ 19
|
|
|
+#define SOFTIRQ_IRQ 21
|
|
|
+
|
|
|
static char smp_cpuinfo_buf[128];
|
|
|
static int idu_detected;
|
|
|
|
|
@@ -22,6 +26,7 @@ static DEFINE_RAW_SPINLOCK(mcip_lock);
|
|
|
static void mcip_setup_per_cpu(int cpu)
|
|
|
{
|
|
|
smp_ipi_irq_setup(cpu, IPI_IRQ);
|
|
|
+ smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ);
|
|
|
}
|
|
|
|
|
|
static void mcip_ipi_send(int cpu)
|
|
@@ -29,46 +34,44 @@ static void mcip_ipi_send(int cpu)
|
|
|
unsigned long flags;
|
|
|
int ipi_was_pending;
|
|
|
|
|
|
+ /* ARConnect can only send IPI to others */
|
|
|
+ if (unlikely(cpu == raw_smp_processor_id())) {
|
|
|
+ arc_softirq_trigger(SOFTIRQ_IRQ);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&mcip_lock, flags);
|
|
|
+
|
|
|
/*
|
|
|
- * NOTE: We must spin here if the other cpu hasn't yet
|
|
|
- * serviced a previous message. This can burn lots
|
|
|
- * of time, but we MUST follows this protocol or
|
|
|
- * ipi messages can be lost!!!
|
|
|
- * Also, we must release the lock in this loop because
|
|
|
- * the other side may get to this same loop and not
|
|
|
- * be able to ack -- thus causing deadlock.
|
|
|
+ * If receiver already has a pending interrupt, elide sending this one.
|
|
|
+ * Linux cross core calling works well with concurrent IPIs
|
|
|
+ * coalesced into one
|
|
|
+ * see arch/arc/kernel/smp.c: ipi_send_msg_one()
|
|
|
*/
|
|
|
+ __mcip_cmd(CMD_INTRPT_READ_STATUS, cpu);
|
|
|
+ ipi_was_pending = read_aux_reg(ARC_REG_MCIP_READBACK);
|
|
|
+ if (!ipi_was_pending)
|
|
|
+ __mcip_cmd(CMD_INTRPT_GENERATE_IRQ, cpu);
|
|
|
|
|
|
- do {
|
|
|
- raw_spin_lock_irqsave(&mcip_lock, flags);
|
|
|
- __mcip_cmd(CMD_INTRPT_READ_STATUS, cpu);
|
|
|
- ipi_was_pending = read_aux_reg(ARC_REG_MCIP_READBACK);
|
|
|
- if (ipi_was_pending == 0)
|
|
|
- break; /* break out but keep lock */
|
|
|
- raw_spin_unlock_irqrestore(&mcip_lock, flags);
|
|
|
- } while (1);
|
|
|
-
|
|
|
- __mcip_cmd(CMD_INTRPT_GENERATE_IRQ, cpu);
|
|
|
raw_spin_unlock_irqrestore(&mcip_lock, flags);
|
|
|
-
|
|
|
-#ifdef CONFIG_ARC_IPI_DBG
|
|
|
- if (ipi_was_pending)
|
|
|
- pr_info("IPI ACK delayed from cpu %d\n", cpu);
|
|
|
-#endif
|
|
|
}
|
|
|
|
|
|
static void mcip_ipi_clear(int irq)
|
|
|
{
|
|
|
unsigned int cpu, c;
|
|
|
unsigned long flags;
|
|
|
- unsigned int __maybe_unused copy;
|
|
|
+
|
|
|
+ if (unlikely(irq == SOFTIRQ_IRQ)) {
|
|
|
+ arc_softirq_clear(irq);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
raw_spin_lock_irqsave(&mcip_lock, flags);
|
|
|
|
|
|
/* Who sent the IPI */
|
|
|
__mcip_cmd(CMD_INTRPT_CHECK_SOURCE, 0);
|
|
|
|
|
|
- copy = cpu = read_aux_reg(ARC_REG_MCIP_READBACK); /* 1,2,4,8... */
|
|
|
+ cpu = read_aux_reg(ARC_REG_MCIP_READBACK); /* 1,2,4,8... */
|
|
|
|
|
|
/*
|
|
|
* In rare case, multiple concurrent IPIs sent to same target can
|
|
@@ -82,12 +85,6 @@ static void mcip_ipi_clear(int irq)
|
|
|
} while (cpu);
|
|
|
|
|
|
raw_spin_unlock_irqrestore(&mcip_lock, flags);
|
|
|
-
|
|
|
-#ifdef CONFIG_ARC_IPI_DBG
|
|
|
- if (c != __ffs(copy))
|
|
|
- pr_info("IPIs from %x coalesced to %x\n",
|
|
|
- copy, raw_smp_processor_id());
|
|
|
-#endif
|
|
|
}
|
|
|
|
|
|
static void mcip_probe_n_setup(void)
|
|
@@ -111,10 +108,11 @@ static void mcip_probe_n_setup(void)
|
|
|
READ_BCR(ARC_REG_MCIP_BCR, mp);
|
|
|
|
|
|
sprintf(smp_cpuinfo_buf,
|
|
|
- "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n",
|
|
|
+ "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s%s\n",
|
|
|
mp.ver, mp.num_cores,
|
|
|
IS_AVAIL1(mp.ipi, "IPI "),
|
|
|
IS_AVAIL1(mp.idu, "IDU "),
|
|
|
+ IS_AVAIL1(mp.llm, "LLM "),
|
|
|
IS_AVAIL1(mp.dbg, "DEBUG "),
|
|
|
IS_AVAIL1(mp.gfrc, "GFRC"));
|
|
|
|