Re: [PATCH 2/5] VIRT: Support runtime irq_bypass consumer

2015-12-16 Thread Alex Williamson
On Thu, 2015-12-03 at 10:22 -0800, Yunhong Jiang wrote:
> Extend the irq_bypass manager to support runtime consumers. A runtime
> irq_bypass consumer can handle interrupt when an interrupt triggered. A
> runtime consumer has it's handle_irq() function set and passing a
> irq_context for the irq handling.
> 
> A producer keep a link for the runtime consumers, so that it can invoke
> each consumer's handle_irq() when irq invoked.
> 
> Currently the irq_bypass manager has several code path assuming there is
> only one consumer/producer pair for each token. For example, when
> register the producer, it exits the loop after finding one match
> consumer.  This is updated to support both static consumer (like for
> Posted Interrupt consumer) and runtime consumer.
> 
> Signed-off-by: Yunhong Jiang 
> ---
>  include/linux/irqbypass.h |  8 +
>  virt/lib/irqbypass.c  | 82 
> +++
>  2 files changed, 69 insertions(+), 21 deletions(-)
> 
> diff --git a/include/linux/irqbypass.h b/include/linux/irqbypass.h
> index 1551b5b2f4c2..d5bec0c7be3a 100644
> --- a/include/linux/irqbypass.h
> +++ b/include/linux/irqbypass.h
> @@ -12,6 +12,7 @@
>  #define IRQBYPASS_H
>  
>  #include 
> +#include 
>  
>  struct irq_bypass_consumer;
>  
> @@ -47,6 +48,9 @@ struct irq_bypass_consumer;
>   */
>  struct irq_bypass_producer {
>   struct list_head node;
> + /* Update side is synchronized by the lock on irqbypass.c */
> + struct srcu_struct srcu;
> + struct list_head consumers;
>   void *token;
>   int irq;
>   int (*add_consumer)(struct irq_bypass_producer *,

Documentation?

> @@ -61,6 +65,7 @@ struct irq_bypass_producer {
>   * struct irq_bypass_consumer - IRQ bypass consumer definition
>   * @node: IRQ bypass manager private list management
>   * @token: opaque token to match between producer and consumer
> + * @sibling: consumers with same token list management
>   * @add_producer: Connect the IRQ consumer to an IRQ producer
>   * @del_producer: Disconnect the IRQ consumer from an IRQ producer
>   * @stop: Perform any quiesce operations necessary prior to add/del 
> (optional)

What about @handle_irq and @irq_context?

> @@ -73,6 +78,7 @@ struct irq_bypass_producer {
>   */
>  struct irq_bypass_consumer {
>   struct list_head node;
> + struct list_head sibling;
>   void *token;
>   int (*add_producer)(struct irq_bypass_consumer *,
>   struct irq_bypass_producer *);
> @@ -80,6 +86,8 @@ struct irq_bypass_consumer {
>    struct irq_bypass_producer *);
>   void (*stop)(struct irq_bypass_consumer *);
>   void (*start)(struct irq_bypass_consumer *);
> + int (*handle_irq)(void *arg);

If we called this with a pointer to the consumer, like the other
functions, the consumer could embed arg (irq_context) into their own
structure, or in this case, do a container_of and avoid storing the
irqfd pointer entirely.

> + void *irq_context;
>  };
>  
>  int irq_bypass_register_producer(struct irq_bypass_producer *);
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/5] VIRT: Support runtime irq_bypass consumer

2015-12-03 Thread Yunhong Jiang
Extend the irq_bypass manager to support runtime consumers. A runtime
irq_bypass consumer can handle interrupt when an interrupt triggered. A
runtime consumer has it's handle_irq() function set and passing a
irq_context for the irq handling.

A producer keep a link for the runtime consumers, so that it can invoke
each consumer's handle_irq() when irq invoked.

Currently the irq_bypass manager has several code path assuming there is
only one consumer/producer pair for each token. For example, when
register the producer, it exits the loop after finding one match
consumer.  This is updated to support both static consumer (like for
Posted Interrupt consumer) and runtime consumer.

Signed-off-by: Yunhong Jiang 
---
 include/linux/irqbypass.h |  8 +
 virt/lib/irqbypass.c  | 82 +++
 2 files changed, 69 insertions(+), 21 deletions(-)

diff --git a/include/linux/irqbypass.h b/include/linux/irqbypass.h
index 1551b5b2f4c2..d5bec0c7be3a 100644
--- a/include/linux/irqbypass.h
+++ b/include/linux/irqbypass.h
@@ -12,6 +12,7 @@
 #define IRQBYPASS_H
 
 #include 
+#include 
 
 struct irq_bypass_consumer;
 
@@ -47,6 +48,9 @@ struct irq_bypass_consumer;
  */
 struct irq_bypass_producer {
struct list_head node;
+   /* Update side is synchronized by the lock on irqbypass.c */
+   struct srcu_struct srcu;
+   struct list_head consumers;
void *token;
int irq;
int (*add_consumer)(struct irq_bypass_producer *,
@@ -61,6 +65,7 @@ struct irq_bypass_producer {
  * struct irq_bypass_consumer - IRQ bypass consumer definition
  * @node: IRQ bypass manager private list management
  * @token: opaque token to match between producer and consumer
+ * @sibling: consumers with same token list management
  * @add_producer: Connect the IRQ consumer to an IRQ producer
  * @del_producer: Disconnect the IRQ consumer from an IRQ producer
  * @stop: Perform any quiesce operations necessary prior to add/del (optional)
@@ -73,6 +78,7 @@ struct irq_bypass_producer {
  */
 struct irq_bypass_consumer {
struct list_head node;
+   struct list_head sibling;
void *token;
int (*add_producer)(struct irq_bypass_consumer *,
struct irq_bypass_producer *);
@@ -80,6 +86,8 @@ struct irq_bypass_consumer {
 struct irq_bypass_producer *);
void (*stop)(struct irq_bypass_consumer *);
void (*start)(struct irq_bypass_consumer *);
+   int (*handle_irq)(void *arg);
+   void *irq_context;
 };
 
 int irq_bypass_register_producer(struct irq_bypass_producer *);
diff --git a/virt/lib/irqbypass.c b/virt/lib/irqbypass.c
index 09a03b5a21ff..43ef9e2c77dc 100644
--- a/virt/lib/irqbypass.c
+++ b/virt/lib/irqbypass.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("IRQ bypass manager utility module");
@@ -49,11 +50,8 @@ static int __connect(struct irq_bypass_producer *prod,
prod->del_consumer(prod, cons);
}
 
-   if (cons->start)
-   cons->start(cons);
-   if (prod->start)
-   prod->start(prod);
-
+   if (!ret && cons->handle_irq)
+   list_add_rcu(&cons->sibling, &prod->consumers);
return ret;
 }
 
@@ -71,6 +69,11 @@ static void __disconnect(struct irq_bypass_producer *prod,
if (prod->del_consumer)
prod->del_consumer(prod, cons);
 
+   if (cons->handle_irq) {
+   list_del_rcu(&cons->sibling);
+   synchronize_srcu(&prod->srcu);
+   }
+
if (cons->start)
cons->start(cons);
if (prod->start)
@@ -87,7 +90,8 @@ static void __disconnect(struct irq_bypass_producer *prod,
 int irq_bypass_register_producer(struct irq_bypass_producer *producer)
 {
struct irq_bypass_producer *tmp;
-   struct irq_bypass_consumer *consumer;
+   struct list_head *node, *next, siblings = LIST_HEAD_INIT(siblings);
+   int ret;
 
might_sleep();
 
@@ -96,6 +100,9 @@ int irq_bypass_register_producer(struct irq_bypass_producer 
*producer)
 
mutex_lock(&lock);
 
+   INIT_LIST_HEAD(&producer->consumers);
+   init_srcu_struct(&producer->srcu);
+
list_for_each_entry(tmp, &producers, node) {
if (tmp->token == producer->token) {
mutex_unlock(&lock);
@@ -104,23 +111,48 @@ int irq_bypass_register_producer(struct 
irq_bypass_producer *producer)
}
}
 
-   list_for_each_entry(consumer, &consumers, node) {
+   list_for_each_safe(node, next, &consumers) {
+   struct irq_bypass_consumer *consumer = container_of(
+   node, struct irq_bypass_consumer, node);
+
if (consumer->token == producer->token) {
-   int ret = __connect(producer, consumer);
-   if (ret) {
-   mutex_unl