With the new generic smp call function helpers, I noticed the code in
smp_message_recv was a single function call in many cases.  While
getting the message number from the ipi data is easy, we can reduce
the path length by a function and data dependent switch by registering
seperate ipi actions for these simple calls.

Originally I left the ipi action array exposed, but then I realized the
registration code should be common too.

The three users each had their own name array, so I made a fourth
to convert all users to use a common one.

Signed-off-by: Milton Miller <[EMAIL PROTECTED]>
---
Perhaps we should make the common code look like an ipi action handler
and remove this last call?  Currently we still have to allocate a stack
frame to load the return value.

v2: fix arg reversal noted by Geert Uytterhoeven

v3: fix missed variable rename in WARN

I was going to make the variable local, then wanted it global for
the error request cases, and missed the instance when WARN was not
evaluating the printk for powerpc.

Unfornately, it appears that we are somewhat unique with one external
interrupt but multiple ipi vectors: a grep of arch/*/kernel/* for
generic_call_function_interrupt shows:

alpha, arm, ia64, parisc, 390 demux messages on a sw bitvector (although
many use spinlock/read/clear/unlock vs our test and clear bit), and
x86, mips, and m32r demux before get_irq, directly calling irq_enter/irq_exit,
leaving sh as the only one that has multiple ipis but uses request_irq/get_irq,
and they clear the source bit in the caller to the message demux and would
have minimal benefit from a signature change (they could get tail call
but not direct call).  They could gain to a similar change to this.

Index: next.git/arch/powerpc/include/asm/smp.h
===================================================================
--- next.git.orig/arch/powerpc/include/asm/smp.h        2008-10-22 
07:10:11.000000000 -0500
+++ next.git/arch/powerpc/include/asm/smp.h     2008-11-10 22:37:52.000000000 
-0600
@@ -81,6 +81,13 @@ extern int cpu_to_core_id(int cpu);
 #define PPC_MSG_CALL_FUNC_SINGLE       2
 #define PPC_MSG_DEBUGGER_BREAK  3
 
+/*
+ * irq controllers that have dedicated ipis per message and don't
+ * need additional code in the action handler may use this
+ */
+extern int smp_request_message_ipi(int virq, int message);
+extern const char *smp_ipi_name[];
+
 void smp_init_iSeries(void);
 void smp_init_pSeries(void);
 void smp_init_cell(void);
Index: next.git/arch/powerpc/kernel/smp.c
===================================================================
--- next.git.orig/arch/powerpc/kernel/smp.c     2008-10-22 07:10:11.000000000 
-0500
+++ next.git/arch/powerpc/kernel/smp.c  2008-11-10 22:38:16.000000000 -0600
@@ -123,6 +123,65 @@ void smp_message_recv(int msg)
        }
 }
 
+static irqreturn_t call_function_action(int irq, void *data)
+{
+       generic_smp_call_function_interrupt();
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t reschedule_action(int irq, void *data)
+{
+       /* we just need the return path side effect of checking need_resched */
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t call_function_single_action(int irq, void *data)
+{
+       generic_smp_call_function_single_interrupt();
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t debug_ipi_action(int irq, void *data)
+{
+       smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
+       return IRQ_HANDLED;
+}
+
+static irq_handler_t smp_ipi_action[] = {
+       [PPC_MSG_CALL_FUNCTION] =  call_function_action,
+       [PPC_MSG_RESCHEDULE] = reschedule_action,
+       [PPC_MSG_CALL_FUNC_SINGLE] = call_function_single_action,
+       [PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action,
+};
+
+const char *smp_ipi_name[] = {
+       [PPC_MSG_CALL_FUNCTION] =  "ipi call function",
+       [PPC_MSG_RESCHEDULE] = "ipi reschedule",
+       [PPC_MSG_CALL_FUNC_SINGLE] = "ipi call function single",
+       [PPC_MSG_DEBUGGER_BREAK] = "ipi debugger",
+};
+
+/* optional function to request ipi, for controllers with >= 4 ipis */
+int smp_request_message_ipi(int virq, int msg)
+{
+       int err;
+
+       if (msg < 0 || msg > PPC_MSG_DEBUGGER_BREAK) {
+               return -EINVAL;
+       }
+#if !defined(CONFIG_DEBUGGER) && !defined(CONFIG_KEXEC)
+       if (msg == PPC_MSG_DEBUGGER_BREAK) {
+               return 1;
+       }
+#endif
+       err = request_irq(virq, smp_ipi_action[msg], IRQF_DISABLED|IRQF_PERCPU,
+                         smp_ipi_name[msg], 0);
+       WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n",
+               virq, smp_ipi_name[msg], err);
+
+       return err;
+}
+
 void smp_send_reschedule(int cpu)
 {
        if (likely(smp_ops))

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to