diff mbox series

[V6] gpio: virtio: Add IRQ support

Message ID 8ca87330fd348fc5199ad08904ec90cc6a91a1bf.1634723848.git.viresh.kumar@linaro.org
State New
Headers show
Series [V6] gpio: virtio: Add IRQ support | expand

Commit Message

Viresh Kumar Oct. 20, 2021, 10:05 a.m. UTC
This patch adds IRQ support for the virtio GPIO driver. Note that this
uses the irq_bus_lock/unlock() callbacks, since those operations over
virtio may sleep.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
Bartosz,

The spec changes are close to merging now, I will let you know once the ballot
is closed and the spec changes are merged. You can then pick this patch for
5.16.

V5->V6:
- Sent it separately as the other patches are already merged.
- Queue the buffers only after enabling the irq (as per latest spec).
- Migrate to raw_spinlock_t.

 drivers/gpio/Kconfig             |   1 +
 drivers/gpio/gpio-virtio.c       | 310 ++++++++++++++++++++++++++++++-
 include/uapi/linux/virtio_gpio.h |  25 +++
 3 files changed, 332 insertions(+), 4 deletions(-)

Comments

Viresh Kumar Oct. 21, 2021, 4:34 a.m. UTC | #1
On 20-10-21, 18:10, Andy Shevchenko wrote:
> On Wednesday, October 20, 2021, Viresh Kumar <viresh.kumar@linaro.org>
> wrote:
> > +static int virtio_gpio_irq_set_type(struct irq_data *d, unsigned int
> > type)
> > +{
> > +       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
> > +       struct virtio_gpio *vgpio = gpiochip_get_data(gc);
> > +       struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
> > +
> > +       switch (type) {
> > +       case IRQ_TYPE_NONE:
> > +               type = VIRTIO_GPIO_IRQ_TYPE_NONE;
> > +               break;
> 
> 
> IIRC you add dead code. IRQ framework never calls this if type is not set.

Yes, but it is allowed to call

irq_set_irq_type(irq, IRQ_TYPE_NONE);

and the irq framework won't disallow it AFAICT.

> > +static void virtio_gpio_event_vq(struct virtqueue *vq)
> > +{

> > +               irq = irq_find_mapping(vgpio->gc.irq.domain, gpio);
> > +               WARN_ON(!irq);
> > +
> > +               ret = generic_handle_irq(irq);
> 
> 
> IIRC there is a new API that basically combines the two above.

generic_handle_domain_irq(), thanks.

> >  struct virtio_gpio_config {
> >         __le16 ngpio;
> >         __u8 padding[2];
> > @@ -44,4 +56,17 @@ struct virtio_gpio_response_get_names {
> >         __u8 value[];
> >  };
> >
> > +/* Virtio GPIO IRQ Request / Response */
> > +struct virtio_gpio_irq_request {
> > +       __le16 gpio;
> > +};
> > +
> > +struct virtio_gpio_irq_response {
> > +       __u8 status;
> > +};
> >
> >
> I’m wondering if those above should be packed.

You are talking about the newly added ones or the ones before ?

In any case, they are all already packed (i.e. they have explicit
padding wherever required) and properly aligned. Compiler won't add
any other padding to them.
Andy Shevchenko Oct. 21, 2021, 9:42 a.m. UTC | #2
On Thu, Oct 21, 2021 at 7:34 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> On 20-10-21, 18:10, Andy Shevchenko wrote:
> > On Wednesday, October 20, 2021, Viresh Kumar <viresh.kumar@linaro.org>
> > wrote:

...

> > > +       case IRQ_TYPE_NONE:
> > > +               type = VIRTIO_GPIO_IRQ_TYPE_NONE;
> > > +               break;
> >
> > IIRC you add dead code. IRQ framework never calls this if type is not set.
>
> Yes, but it is allowed to call
>
> irq_set_irq_type(irq, IRQ_TYPE_NONE);
>
> and the irq framework won't disallow it AFAICT.

That's true, but how you may end up in this callback with a such?
What the meaning of that call to the user?

...

> > >  struct virtio_gpio_config {
> > >         __le16 ngpio;
> > >         __u8 padding[2];
> > > @@ -44,4 +56,17 @@ struct virtio_gpio_response_get_names {
> > >         __u8 value[];
> > >  };
> > >
> > > +/* Virtio GPIO IRQ Request / Response */
> > > +struct virtio_gpio_irq_request {
> > > +       __le16 gpio;
> > > +};
> > > +
> > > +struct virtio_gpio_irq_response {
> > > +       __u8 status;
> > > +};
> > >
> > I’m wondering if those above should be packed.
>
> You are talking about the newly added ones or the ones before ?
>
> In any case, they are all already packed (i.e. they have explicit
> padding wherever required) and properly aligned. Compiler won't add
> any other padding to them.

Is it only for 64-bit to 64-bit communications?
If there is a possibility to have 32-bit to 64-bit or vice versa
communication you have a problem.
Viresh Kumar Oct. 21, 2021, 9:52 a.m. UTC | #3
On 21-10-21, 12:42, Andy Shevchenko wrote:
> On Thu, Oct 21, 2021 at 7:34 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > On 20-10-21, 18:10, Andy Shevchenko wrote:
> > > IIRC you add dead code. IRQ framework never calls this if type is not set.
> >
> > Yes, but it is allowed to call
> >
> > irq_set_irq_type(irq, IRQ_TYPE_NONE);
> >
> > and the irq framework won't disallow it AFAICT.
> 
> That's true, but how you may end up in this callback with a such?
> What the meaning of that call to the user?
 
I can see few calls like this in the kernel (mostly from irq-providers
only), but yeah sure I can drop it. We will error out if it ever gets
called and so can get it back later if required.
 
> > > >  struct virtio_gpio_config {
> > > >         __le16 ngpio;
> > > >         __u8 padding[2];
> > > > @@ -44,4 +56,17 @@ struct virtio_gpio_response_get_names {
> > > >         __u8 value[];
> > > >  };
> > > >
> > > > +/* Virtio GPIO IRQ Request / Response */
> > > > +struct virtio_gpio_irq_request {
> > > > +       __le16 gpio;
> > > > +};
> > > > +
> > > > +struct virtio_gpio_irq_response {
> > > > +       __u8 status;
> > > > +};
> > > >
> > > I’m wondering if those above should be packed.
> >
> > You are talking about the newly added ones or the ones before ?
> >
> > In any case, they are all already packed (i.e. they have explicit
> > padding wherever required) and properly aligned. Compiler won't add
> > any other padding to them.
> 
> Is it only for 64-bit to 64-bit communications?

That's what I have been looking at.

> If there is a possibility to have 32-bit to 64-bit or vice versa
> communication you have a problem.

This should work as well.

The structure will get aligned to the size of largest element and each
element will be aligned to itself. I don't see how this will break
even in case of 32/64 bit communication.
Andy Shevchenko Oct. 21, 2021, 9:58 a.m. UTC | #4
On Thu, Oct 21, 2021 at 12:52 PM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> On 21-10-21, 12:42, Andy Shevchenko wrote:
> > On Thu, Oct 21, 2021 at 7:34 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > > On 20-10-21, 18:10, Andy Shevchenko wrote:

...

> > > > >  struct virtio_gpio_config {
> > > > >         __le16 ngpio;
> > > > >         __u8 padding[2];
> > > > > @@ -44,4 +56,17 @@ struct virtio_gpio_response_get_names {
> > > > >         __u8 value[];
> > > > >  };
> > > > >
> > > > > +/* Virtio GPIO IRQ Request / Response */
> > > > > +struct virtio_gpio_irq_request {
> > > > > +       __le16 gpio;
> > > > > +};
> > > > > +
> > > > > +struct virtio_gpio_irq_response {
> > > > > +       __u8 status;
> > > > > +};
> > > > >
> > > > I’m wondering if those above should be packed.
> > >
> > > You are talking about the newly added ones or the ones before ?
> > >
> > > In any case, they are all already packed (i.e. they have explicit
> > > padding wherever required) and properly aligned. Compiler won't add
> > > any other padding to them.
> >
> > Is it only for 64-bit to 64-bit communications?
>
> That's what I have been looking at.
>
> > If there is a possibility to have 32-bit to 64-bit or vice versa
> > communication you have a problem.
>
> This should work as well.
>
> The structure will get aligned to the size of largest element and each
> element will be aligned to itself. I don't see how this will break
> even in case of 32/64 bit communication.

I admit I haven't looked into the specification, but in the past we
had had quite an issue exactly in GPIO on kernel side because of this
kind of design mistake. The problem here if in the future one wants to
supply more than one item at a time, it will be not possible with this
interface. Yes, I understand that in current design it's rather missed
scalability, but hey, I believe in the future we may need
performance-wise calls.
Viresh Kumar Oct. 21, 2021, 10:02 a.m. UTC | #5
On 21-10-21, 12:58, Andy Shevchenko wrote:
> I admit I haven't looked into the specification, but in the past we
> had had quite an issue exactly in GPIO on kernel side because of this
> kind of design mistake.

> The problem here if in the future one wants to
> supply more than one item at a time, it will be not possible with this
> interface.

Why ?

> Yes, I understand that in current design it's rather missed
> scalability, but hey, I believe in the future we may need
> performance-wise calls.
Geert Uytterhoeven Oct. 21, 2021, 10:07 a.m. UTC | #6
Hi Viresh,

On Thu, Oct 21, 2021 at 11:52 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> The structure will get aligned to the size of largest element and each
> element will be aligned to itself. I don't see how this will break
> even in case of 32/64 bit communication.

Structures are not aligned to the size of the largest element, but
to the largest alignment needed for each member.
This can be smaller than the size of the largest element.
E.g. alignof(long long) might be 4, not 8.  And m68k aligns to
two bytes at most.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Arnd Bergmann Oct. 21, 2021, 10:47 a.m. UTC | #7
On Thu, Oct 21, 2021 at 11:58 AM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Thu, Oct 21, 2021 at 12:52 PM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > On 21-10-21, 12:42, Andy Shevchenko wrote:
> > > On Thu, Oct 21, 2021 at 7:34 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > > > On 20-10-21, 18:10, Andy Shevchenko wrote:
> >
> > > If there is a possibility to have 32-bit to 64-bit or vice versa
> > > communication you have a problem.
> >
> > This should work as well.
> >
> > The structure will get aligned to the size of largest element and each
> > element will be aligned to itself. I don't see how this will break
> > even in case of 32/64 bit communication.
>
> I admit I haven't looked into the specification, but in the past we
> had had quite an issue exactly in GPIO on kernel side because of this
> kind of design mistake. The problem here if in the future one wants to
> supply more than one item at a time, it will be not possible with this
> interface. Yes, I understand that in current design it's rather missed
> scalability, but hey, I believe in the future we may need
> performance-wise calls.

In my experience, adding __packed to structures causes more problems
than it solves, please don't do that.

The rules for the virtio structures should be roughly the same that I
documented in Documentation/driver-api/ioctl.rst, and the layout that
Viresh has picked does not suffer from any of the common issues
that are listed there.

       Arnd
Viresh Kumar Oct. 21, 2021, 10:49 a.m. UTC | #8
On 21-10-21, 12:07, Geert Uytterhoeven wrote:
> On Thu, Oct 21, 2021 at 11:52 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > The structure will get aligned to the size of largest element and each
> > element will be aligned to itself. I don't see how this will break
> > even in case of 32/64 bit communication.
> 
> Structures are not aligned to the size of the largest element, but
> to the largest alignment needed for each member.

Right, I was talking in terms of the structures we have here for GPIO.
The biggest member here (for any structure) is 32bits long, and
compiler shouldn't add extra padding here.

> This can be smaller than the size of the largest element.
> E.g. alignof(long long) might be 4, not 8. 

Right.

> And m68k aligns to two bytes at most.

Interesting, I assumed that it will be 4bytes for 32 bit systems. So
in case of m68k, we will see something like this ?

struct foo {
    u8 a;       // aligned to 2 bytes

                // padding of 1 byte

    u32 b;      // aligned to 2 bytes
}
Geert Uytterhoeven Oct. 21, 2021, 11:02 a.m. UTC | #9
Hi Viresh,

On Thu, Oct 21, 2021 at 12:49 PM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> On 21-10-21, 12:07, Geert Uytterhoeven wrote:
> > On Thu, Oct 21, 2021 at 11:52 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > > The structure will get aligned to the size of largest element and each
> > > element will be aligned to itself. I don't see how this will break
> > > even in case of 32/64 bit communication.
> >
> > Structures are not aligned to the size of the largest element, but
> > to the largest alignment needed for each member.
>
> Right, I was talking in terms of the structures we have here for GPIO.
> The biggest member here (for any structure) is 32bits long, and
> compiler shouldn't add extra padding here.
>
> > This can be smaller than the size of the largest element.
> > E.g. alignof(long long) might be 4, not 8.
>
> Right.
>
> > And m68k aligns to two bytes at most.
>
> Interesting, I assumed that it will be 4bytes for 32 bit systems. So
> in case of m68k, we will see something like this ?
>
> struct foo {
>     u8 a;       // aligned to 2 bytes
>
>                 // padding of 1 byte
>
>     u32 b;      // aligned to 2 bytes
> }

Exactly.  And on CRIS (no longer supported by Linux), there won't
be any padding.

So I recommend to always add explicit padding, to make sure all
members are aligned naturally on all systems.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Viresh Kumar Oct. 21, 2021, 11:04 a.m. UTC | #10
On 21-10-21, 13:02, Geert Uytterhoeven wrote:
> Exactly.  And on CRIS (no longer supported by Linux), there won't
> be any padding.
> 
> So I recommend to always add explicit padding, to make sure all
> members are aligned naturally on all systems.

Right.
diff mbox series

Patch

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index fae5141251e5..bfa723ff8e7c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1674,6 +1674,7 @@  config GPIO_MOCKUP
 config GPIO_VIRTIO
 	tristate "VirtIO GPIO support"
 	depends on VIRTIO
+	select GPIOLIB_IRQCHIP
 	help
 	  Say Y here to enable guest support for virtio-based GPIO controllers.
 
diff --git a/drivers/gpio/gpio-virtio.c b/drivers/gpio/gpio-virtio.c
index d24f1c9264bc..73fbe2eda4b9 100644
--- a/drivers/gpio/gpio-virtio.c
+++ b/drivers/gpio/gpio-virtio.c
@@ -16,6 +16,7 @@ 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/virtio_config.h>
 #include <uapi/linux/virtio_gpio.h>
 #include <uapi/linux/virtio_ids.h>
@@ -28,12 +29,30 @@  struct virtio_gpio_line {
 	unsigned int rxlen;
 };
 
+struct vgpio_irq_line {
+	u8 type;
+	bool disabled;
+	bool masked;
+	bool queued;
+	bool update_pending;
+	bool queue_pending;
+
+	struct virtio_gpio_irq_request ireq ____cacheline_aligned;
+	struct virtio_gpio_irq_response ires ____cacheline_aligned;
+};
+
 struct virtio_gpio {
 	struct virtio_device *vdev;
 	struct mutex lock; /* Protects virtqueue operation */
 	struct gpio_chip gc;
 	struct virtio_gpio_line *lines;
 	struct virtqueue *request_vq;
+
+	/* irq support */
+	struct virtqueue *event_vq;
+	struct mutex irq_lock; /* Protects irq operation */
+	raw_spinlock_t eventq_lock; /* Protects queuing of the buffer */
+	struct vgpio_irq_line *irq_lines;
 };
 
 static int _virtio_gpio_req(struct virtio_gpio *vgpio, u16 type, u16 gpio,
@@ -186,6 +205,244 @@  static void virtio_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
 	virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_VALUE, gpio, value, NULL);
 }
 
+/* Interrupt handling */
+static void virtio_gpio_irq_prepare(struct virtio_gpio *vgpio, u16 gpio)
+{
+	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[gpio];
+	struct virtio_gpio_irq_request *ireq = &irq_line->ireq;
+	struct virtio_gpio_irq_response *ires = &irq_line->ires;
+	struct scatterlist *sgs[2], req_sg, res_sg;
+	int ret;
+
+	if (WARN_ON(irq_line->queued || irq_line->masked || irq_line->disabled))
+		return;
+
+	ireq->gpio = cpu_to_le16(gpio);
+	sg_init_one(&req_sg, ireq, sizeof(*ireq));
+	sg_init_one(&res_sg, ires, sizeof(*ires));
+	sgs[0] = &req_sg;
+	sgs[1] = &res_sg;
+
+	ret = virtqueue_add_sgs(vgpio->event_vq, sgs, 1, 1, irq_line, GFP_ATOMIC);
+	if (ret) {
+		dev_err(&vgpio->vdev->dev, "failed to add request to eventq\n");
+		return;
+	}
+
+	irq_line->queued = true;
+	virtqueue_kick(vgpio->event_vq);
+}
+
+static void virtio_gpio_irq_enable(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
+	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
+
+	raw_spin_lock(&vgpio->eventq_lock);
+	irq_line->disabled = false;
+	irq_line->masked = false;
+	irq_line->queue_pending = true;
+	raw_spin_unlock(&vgpio->eventq_lock);
+
+	irq_line->update_pending = true;
+}
+
+static void virtio_gpio_irq_disable(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
+	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
+
+	raw_spin_lock(&vgpio->eventq_lock);
+	irq_line->disabled = true;
+	irq_line->masked = true;
+	irq_line->queue_pending = false;
+	raw_spin_unlock(&vgpio->eventq_lock);
+
+	irq_line->update_pending = true;
+}
+
+static void virtio_gpio_irq_mask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
+	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
+
+	raw_spin_lock(&vgpio->eventq_lock);
+	irq_line->masked = true;
+	raw_spin_unlock(&vgpio->eventq_lock);
+}
+
+static void virtio_gpio_irq_unmask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
+	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
+
+	raw_spin_lock(&vgpio->eventq_lock);
+	irq_line->masked = false;
+
+	/* Queue the buffer unconditionally on unmask */
+	virtio_gpio_irq_prepare(vgpio, d->hwirq);
+	raw_spin_unlock(&vgpio->eventq_lock);
+}
+
+static int virtio_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
+	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
+
+	switch (type) {
+	case IRQ_TYPE_NONE:
+		type = VIRTIO_GPIO_IRQ_TYPE_NONE;
+		break;
+	case IRQ_TYPE_EDGE_RISING:
+		type = VIRTIO_GPIO_IRQ_TYPE_EDGE_RISING;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		type = VIRTIO_GPIO_IRQ_TYPE_EDGE_FALLING;
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		type = VIRTIO_GPIO_IRQ_TYPE_EDGE_BOTH;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		type = VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		type = VIRTIO_GPIO_IRQ_TYPE_LEVEL_HIGH;
+		break;
+	default:
+		dev_err(&vgpio->vdev->dev, "unsupported irq type: %u\n", type);
+		return -EINVAL;
+	}
+
+	irq_line->type = type;
+	irq_line->update_pending = true;
+
+	return 0;
+}
+
+static void virtio_gpio_irq_bus_lock(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
+
+	mutex_lock(&vgpio->irq_lock);
+}
+
+static void virtio_gpio_irq_bus_sync_unlock(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
+	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
+	u8 type = irq_line->disabled ? VIRTIO_GPIO_IRQ_TYPE_NONE : irq_line->type;
+	unsigned long flags;
+
+	if (irq_line->update_pending) {
+		irq_line->update_pending = false;
+		virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_IRQ_TYPE, d->hwirq, type,
+				NULL);
+
+		/* Queue the buffer only after interrupt is enabled */
+		raw_spin_lock_irqsave(&vgpio->eventq_lock, flags);
+		if (irq_line->queue_pending) {
+			irq_line->queue_pending = false;
+			virtio_gpio_irq_prepare(vgpio, d->hwirq);
+		}
+		raw_spin_unlock_irqrestore(&vgpio->eventq_lock, flags);
+	}
+
+	mutex_unlock(&vgpio->irq_lock);
+}
+
+static struct irq_chip vgpio_irq_chip = {
+	.name			= "virtio-gpio",
+	.irq_enable		= virtio_gpio_irq_enable,
+	.irq_disable		= virtio_gpio_irq_disable,
+	.irq_mask		= virtio_gpio_irq_mask,
+	.irq_unmask		= virtio_gpio_irq_unmask,
+	.irq_set_type		= virtio_gpio_irq_set_type,
+
+	/* These are required to implement irqchip for slow busses */
+	.irq_bus_lock		= virtio_gpio_irq_bus_lock,
+	.irq_bus_sync_unlock	= virtio_gpio_irq_bus_sync_unlock,
+};
+
+static bool ignore_irq(struct virtio_gpio *vgpio, int gpio,
+		       struct vgpio_irq_line *irq_line)
+{
+	bool ignore = false;
+
+	raw_spin_lock(&vgpio->eventq_lock);
+	irq_line->queued = false;
+
+	/* Interrupt is disabled currently */
+	if (irq_line->masked || irq_line->disabled) {
+		ignore = true;
+		goto unlock;
+	}
+
+	/*
+	 * Buffer is returned as the interrupt was disabled earlier, but is
+	 * enabled again now. Requeue the buffers.
+	 */
+	if (irq_line->ires.status == VIRTIO_GPIO_IRQ_STATUS_INVALID) {
+		virtio_gpio_irq_prepare(vgpio, gpio);
+		ignore = true;
+		goto unlock;
+	}
+
+	if (WARN_ON(irq_line->ires.status != VIRTIO_GPIO_IRQ_STATUS_VALID))
+		ignore = true;
+
+unlock:
+	raw_spin_unlock(&vgpio->eventq_lock);
+
+	return ignore;
+}
+
+static void virtio_gpio_event_vq(struct virtqueue *vq)
+{
+	struct virtio_gpio *vgpio = vq->vdev->priv;
+	struct device *dev = &vgpio->vdev->dev;
+	struct vgpio_irq_line *irq_line;
+	int irq, gpio, ret;
+	unsigned int len;
+
+	while (true) {
+		irq_line = virtqueue_get_buf(vgpio->event_vq, &len);
+		if (!irq_line)
+			break;
+
+		if (len != sizeof(irq_line->ires)) {
+			dev_err(dev, "irq with incorrect length (%u : %u)\n",
+				len, (unsigned int)sizeof(irq_line->ires));
+			continue;
+		}
+
+		/*
+		 * Find GPIO line number from the offset of irq_line within the
+		 * irq_lines block. We can also get GPIO number from
+		 * irq-request, but better not to rely on a buffer returned by
+		 * remote.
+		 */
+		gpio = irq_line - vgpio->irq_lines;
+		WARN_ON(gpio >= vgpio->gc.ngpio);
+
+		if (unlikely(ignore_irq(vgpio, gpio, irq_line)))
+			continue;
+
+		irq = irq_find_mapping(vgpio->gc.irq.domain, gpio);
+		WARN_ON(!irq);
+
+		ret = generic_handle_irq(irq);
+		if (ret)
+			dev_err(dev, "failed to handle interrupt: %d\n", ret);
+	};
+}
+
 static void virtio_gpio_request_vq(struct virtqueue *vq)
 {
 	struct virtio_gpio_line *line;
@@ -210,14 +467,15 @@  static void virtio_gpio_free_vqs(struct virtio_device *vdev)
 static int virtio_gpio_alloc_vqs(struct virtio_gpio *vgpio,
 				 struct virtio_device *vdev)
 {
-	const char * const names[] = { "requestq" };
+	const char * const names[] = { "requestq", "eventq" };
 	vq_callback_t *cbs[] = {
 		virtio_gpio_request_vq,
+		virtio_gpio_event_vq,
 	};
-	struct virtqueue *vqs[1] = { NULL };
+	struct virtqueue *vqs[2] = { NULL, NULL };
 	int ret;
 
-	ret = virtio_find_vqs(vdev, 1, vqs, cbs, names, NULL);
+	ret = virtio_find_vqs(vdev, vgpio->irq_lines ? 2 : 1, vqs, cbs, names, NULL);
 	if (ret) {
 		dev_err(&vdev->dev, "failed to find vqs: %d\n", ret);
 		return ret;
@@ -225,11 +483,23 @@  static int virtio_gpio_alloc_vqs(struct virtio_gpio *vgpio,
 
 	if (!vqs[0]) {
 		dev_err(&vdev->dev, "failed to find requestq vq\n");
-		return -ENODEV;
+		goto out;
 	}
 	vgpio->request_vq = vqs[0];
 
+	if (vgpio->irq_lines && !vqs[1]) {
+		dev_err(&vdev->dev, "failed to find eventq vq\n");
+		goto out;
+	}
+	vgpio->event_vq = vqs[1];
+
 	return 0;
+
+out:
+	if (vqs[0] || vqs[1])
+		virtio_gpio_free_vqs(vdev);
+
+	return -ENODEV;
 }
 
 static const char **virtio_gpio_get_names(struct virtio_gpio *vgpio,
@@ -325,6 +595,32 @@  static int virtio_gpio_probe(struct virtio_device *vdev)
 	vgpio->gc.owner			= THIS_MODULE;
 	vgpio->gc.can_sleep		= true;
 
+	/* Interrupt support */
+	if (virtio_has_feature(vdev, VIRTIO_GPIO_F_IRQ)) {
+		vgpio->irq_lines = devm_kcalloc(dev, ngpio,
+						sizeof(*vgpio->irq_lines),
+						GFP_KERNEL);
+		if (!vgpio->irq_lines)
+			return -ENOMEM;
+
+		/* The event comes from the outside so no parent handler */
+		vgpio->gc.irq.parent_handler	= NULL;
+		vgpio->gc.irq.num_parents	= 0;
+		vgpio->gc.irq.parents		= NULL;
+		vgpio->gc.irq.default_type	= IRQ_TYPE_NONE;
+		vgpio->gc.irq.handler		= handle_level_irq;
+		vgpio->gc.irq.chip		= &vgpio_irq_chip;
+
+		for (i = 0; i < ngpio; i++) {
+			vgpio->irq_lines[i].type = VIRTIO_GPIO_IRQ_TYPE_NONE;
+			vgpio->irq_lines[i].disabled = true;
+			vgpio->irq_lines[i].masked = true;
+		}
+
+		mutex_init(&vgpio->irq_lock);
+		raw_spin_lock_init(&vgpio->eventq_lock);
+	}
+
 	ret = virtio_gpio_alloc_vqs(vgpio, vdev);
 	if (ret)
 		return ret;
@@ -357,7 +653,13 @@  static const struct virtio_device_id id_table[] = {
 };
 MODULE_DEVICE_TABLE(virtio, id_table);
 
+static const unsigned int features[] = {
+	VIRTIO_GPIO_F_IRQ,
+};
+
 static struct virtio_driver virtio_gpio_driver = {
+	.feature_table		= features,
+	.feature_table_size	= ARRAY_SIZE(features),
 	.id_table		= id_table,
 	.probe			= virtio_gpio_probe,
 	.remove			= virtio_gpio_remove,
diff --git a/include/uapi/linux/virtio_gpio.h b/include/uapi/linux/virtio_gpio.h
index 0445f905d8cc..d04af9c5f0de 100644
--- a/include/uapi/linux/virtio_gpio.h
+++ b/include/uapi/linux/virtio_gpio.h
@@ -5,12 +5,16 @@ 
 
 #include <linux/types.h>
 
+/* Virtio GPIO Feature bits */
+#define VIRTIO_GPIO_F_IRQ			0
+
 /* Virtio GPIO request types */
 #define VIRTIO_GPIO_MSG_GET_NAMES		0x0001
 #define VIRTIO_GPIO_MSG_GET_DIRECTION		0x0002
 #define VIRTIO_GPIO_MSG_SET_DIRECTION		0x0003
 #define VIRTIO_GPIO_MSG_GET_VALUE		0x0004
 #define VIRTIO_GPIO_MSG_SET_VALUE		0x0005
+#define VIRTIO_GPIO_MSG_IRQ_TYPE		0x0006
 
 /* Possible values of the status field */
 #define VIRTIO_GPIO_STATUS_OK			0x0
@@ -21,6 +25,14 @@ 
 #define VIRTIO_GPIO_DIRECTION_OUT		0x01
 #define VIRTIO_GPIO_DIRECTION_IN		0x02
 
+/* Virtio GPIO IRQ types */
+#define VIRTIO_GPIO_IRQ_TYPE_NONE		0x00
+#define VIRTIO_GPIO_IRQ_TYPE_EDGE_RISING	0x01
+#define VIRTIO_GPIO_IRQ_TYPE_EDGE_FALLING	0x02
+#define VIRTIO_GPIO_IRQ_TYPE_EDGE_BOTH		0x03
+#define VIRTIO_GPIO_IRQ_TYPE_LEVEL_HIGH		0x04
+#define VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW		0x08
+
 struct virtio_gpio_config {
 	__le16 ngpio;
 	__u8 padding[2];
@@ -44,4 +56,17 @@  struct virtio_gpio_response_get_names {
 	__u8 value[];
 };
 
+/* Virtio GPIO IRQ Request / Response */
+struct virtio_gpio_irq_request {
+	__le16 gpio;
+};
+
+struct virtio_gpio_irq_response {
+	__u8 status;
+};
+
+/* Possible values of the interrupt status field */
+#define VIRTIO_GPIO_IRQ_STATUS_INVALID		0x0
+#define VIRTIO_GPIO_IRQ_STATUS_VALID		0x1
+
 #endif /* _LINUX_VIRTIO_GPIO_H */