Blob Blame History Raw
From: jbeulich@novell.com
Subject: netback: use multicall for send multiple notifications
Patch-mainline: obsolete

This also yields a small fairness improvement since now notifications
get sent in the order requests came in rather than in the inverse one.

--- head.orig/drivers/xen/core/evtchn.c	2012-06-08 10:39:44.000000000 +0200
+++ head/drivers/xen/core/evtchn.c	2012-06-08 11:28:28.000000000 +0200
@@ -34,6 +34,7 @@
 #include <linux/slab.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/kconfig.h>
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/ftrace.h>
@@ -1473,6 +1474,27 @@ void notify_remote_via_irq(int irq)
 }
 EXPORT_SYMBOL_GPL(notify_remote_via_irq);
 
+#if IS_ENABLED(CONFIG_XEN_BACKEND)
+int multi_notify_remote_via_irq(multicall_entry_t *mcl, int irq)
+{
+	const struct irq_cfg *cfg = irq_cfg(irq);
+	unsigned int evtchn;
+
+	if (WARN_ON_ONCE(!cfg))
+		return -EINVAL;
+	BUG_ON(type_from_irq_cfg(cfg) == IRQT_VIRQ);
+	BUG_IF_IPI(cfg);
+
+	evtchn = evtchn_from_irq_cfg(cfg);
+	if (!VALID_EVTCHN(evtchn))
+		return -EINVAL;
+
+	multi_notify_remote_via_evtchn(mcl, evtchn);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(multi_notify_remote_via_irq);
+#endif
+
 int irq_to_evtchn_port(int irq)
 {
 	const struct irq_cfg *cfg = irq_cfg(irq);
--- head.orig/drivers/xen/netback/netback.c	2012-06-08 10:42:46.000000000 +0200
+++ head/drivers/xen/netback/netback.c	2012-06-08 10:42:51.000000000 +0200
@@ -773,10 +773,20 @@ static void net_rx_action(unsigned long 
 		npo.meta_cons += nr_frags + 1;
 	}
 
-	while (notify_nr != 0) {
-		irq = notify_list[--notify_nr];
+	if (notify_nr == 1) {
+		irq = *notify_list;
 		__clear_bit(irq, rx_notify);
 		notify_remote_via_irq(irq + DYNIRQ_BASE);
+	} else {
+		for (count = ret = 0; ret < notify_nr; ++ret) {
+			irq = notify_list[ret];
+			__clear_bit(irq, rx_notify);
+			if (!multi_notify_remote_via_irq(rx_mcl + count,
+							 irq + DYNIRQ_BASE))
+				++count;
+		}
+		if (HYPERVISOR_multicall(rx_mcl, count))
+			BUG();
 	}
 
 	/* More work to do? */
--- head.orig/include/xen/evtchn.h	2012-02-10 11:32:59.000000000 +0100
+++ head/include/xen/evtchn.h	2012-02-10 13:35:11.000000000 +0100
@@ -188,6 +188,18 @@ static inline void notify_remote_via_evt
 	VOID(HYPERVISOR_event_channel_op(EVTCHNOP_send, &send));
 }
 
+static inline void
+multi_notify_remote_via_evtchn(multicall_entry_t *mcl, int port)
+{
+	struct evtchn_send *send = (void *)(mcl->args + 2);
+
+	BUILD_BUG_ON(sizeof(*send) > sizeof(mcl->args) - 2 * sizeof(*mcl->args));
+	send->port = port;
+	mcl->op = __HYPERVISOR_event_channel_op;
+	mcl->args[0] = EVTCHNOP_send;
+	mcl->args[1] = (unsigned long)send;
+}
+
 static inline int close_evtchn(int port)
 {
 	struct evtchn_close close = { .port = port };
@@ -202,6 +214,7 @@ int xen_test_irq_pending(int irq);
  * by bind_*_to_irqhandler().
  */
 void notify_remote_via_irq(int irq);
+int multi_notify_remote_via_irq(multicall_entry_t *, int irq);
 int irq_to_evtchn_port(int irq);
 
 #if defined(CONFIG_SMP) && !defined(MODULE) && defined(CONFIG_X86)