summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-01-20 00:18:01 +0000
committerRalf Baechle <ralf@linux-mips.org>2007-01-23 18:26:47 +0000
commitac8be955049dab828a68b9c68a75144832f8289f (patch)
treec9992cccbc6bcb2f099395ef614ebc96b91a2598
parent9ee79a3d372fcb6729893437f4923c5efd1f85db (diff)
[MIPS] SMTC: Instant IPI replay.
SMTC pseudo-interrupts between TCs are deferred and queued if the target TC is interrupt-inhibited (IXMT). In the first SMTC prototypes, these queued IPIs were serviced on return to user mode, or on entry into the kernel idle loop. The INSTANT_REPLAY option dispatches them as part of local_irq_restore() processing, which adds runtime overhead (hence the option to turn it off), but ensures that IPIs are handled promptly even under heavy I/O interrupt load. Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/Kconfig14
-rw-r--r--arch/mips/kernel/smtc.c54
-rw-r--r--include/asm-mips/irqflags.h22
3 files changed, 69 insertions, 21 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index fd2ff0698a8..bbd386f572d 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1568,6 +1568,20 @@ config MIPS_MT_FPAFF
depends on MIPS_MT
default y
+config MIPS_MT_SMTC_INSTANT_REPLAY
+ bool "Low-latency Dispatch of Deferred SMTC IPIs"
+ depends on MIPS_MT_SMTC
+ default y
+ help
+ SMTC pseudo-interrupts between TCs are deferred and queued
+ if the target TC is interrupt-inhibited (IXMT). In the first
+ SMTC prototypes, these queued IPIs were serviced on return
+ to user mode, or on entry into the kernel idle loop. The
+ INSTANT_REPLAY option dispatches them as part of local_irq_restore()
+ processing, which adds runtime overhead (hence the option to turn
+ it off), but ensures that IPIs are handled promptly even under
+ heavy I/O interrupt load.
+
config MIPS_VPE_LOADER_TOM
bool "Load VPE program into memory hidden from linux"
depends on MIPS_VPE_LOADER
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index a8b387197d5..44238ab2fc9 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -1017,6 +1017,33 @@ void setup_cross_vpe_interrupts(void)
* SMTC-specific hacks invoked from elsewhere in the kernel.
*/
+void smtc_ipi_replay(void)
+{
+ /*
+ * To the extent that we've ever turned interrupts off,
+ * we may have accumulated deferred IPIs. This is subtle.
+ * If we use the smtc_ipi_qdepth() macro, we'll get an
+ * exact number - but we'll also disable interrupts
+ * and create a window of failure where a new IPI gets
+ * queued after we test the depth but before we re-enable
+ * interrupts. So long as IXMT never gets set, however,
+ * we should be OK: If we pick up something and dispatch
+ * it here, that's great. If we see nothing, but concurrent
+ * with this operation, another TC sends us an IPI, IXMT
+ * is clear, and we'll handle it as a real pseudo-interrupt
+ * and not a pseudo-pseudo interrupt.
+ */
+ if (IPIQ[smp_processor_id()].depth > 0) {
+ struct smtc_ipi *pipi;
+ extern void self_ipi(struct smtc_ipi *);
+
+ while ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()]))) {
+ self_ipi(pipi);
+ smtc_cpu_stats[smp_processor_id()].selfipis++;
+ }
+ }
+}
+
void smtc_idle_loop_hook(void)
{
#ifdef SMTC_IDLE_HOOK_DEBUG
@@ -1113,29 +1140,14 @@ void smtc_idle_loop_hook(void)
if (pdb_msg != &id_ho_db_msg[0])
printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg);
#endif /* SMTC_IDLE_HOOK_DEBUG */
+
/*
- * To the extent that we've ever turned interrupts off,
- * we may have accumulated deferred IPIs. This is subtle.
- * If we use the smtc_ipi_qdepth() macro, we'll get an
- * exact number - but we'll also disable interrupts
- * and create a window of failure where a new IPI gets
- * queued after we test the depth but before we re-enable
- * interrupts. So long as IXMT never gets set, however,
- * we should be OK: If we pick up something and dispatch
- * it here, that's great. If we see nothing, but concurrent
- * with this operation, another TC sends us an IPI, IXMT
- * is clear, and we'll handle it as a real pseudo-interrupt
- * and not a pseudo-pseudo interrupt.
+ * Replay any accumulated deferred IPIs. If "Instant Replay"
+ * is in use, there should never be any.
*/
- if (IPIQ[smp_processor_id()].depth > 0) {
- struct smtc_ipi *pipi;
- extern void self_ipi(struct smtc_ipi *);
-
- if ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()])) != NULL) {
- self_ipi(pipi);
- smtc_cpu_stats[smp_processor_id()].selfipis++;
- }
- }
+#ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
+ smtc_ipi_replay();
+#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
}
void smtc_soft_dump(void)
diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h
index 46bf5de5ac7..af3b07dfad4 100644
--- a/include/asm-mips/irqflags.h
+++ b/include/asm-mips/irqflags.h
@@ -15,6 +15,27 @@
#include <asm/hazards.h>
+/*
+ * CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY does prompt replay of deferred IPIs,
+ * at the cost of branch and call overhead on each local_irq_restore()
+ */
+
+#ifdef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
+
+extern void smtc_ipi_replay(void);
+
+#define irq_restore_epilog(flags) \
+do { \
+ if (!(flags & 0x0400)) \
+ smtc_ipi_replay(); \
+} while (0)
+
+#else
+
+#define irq_restore_epilog(ignore) do { } while (0)
+
+#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
+
__asm__ (
" .macro raw_local_irq_enable \n"
" .set push \n"
@@ -193,6 +214,7 @@ do { \
: "=r" (__tmp1) \
: "0" (flags) \
: "memory"); \
+ irq_restore_epilog(flags); \
} while(0)
static inline int raw_irqs_disabled_flags(unsigned long flags)