diff mbox series

drivers: gpio: add virtio-gpio guest driver

Message ID 20210615174911.973-1-info@metux.net (mailing list archive)
State New, archived
Headers show
Series drivers: gpio: add virtio-gpio guest driver | expand

Commit Message

Enrico Weigelt, metux IT consult June 15, 2021, 5:49 p.m. UTC
Introduce new GPIO driver for virtual GPIO devices via virtio.

The driver implements the virtio-gpio protocol (ID 41), which can be
used by either VM guests (e.g. bridging virtual gpios from the guest
to real gpios in the host or attaching simulators for automatic
application testing), as well as virtio-gpio hardware devices.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>

---

Status:
    * this driver is now field tested for about 6 month
      (against KVM+Qemu as well as some HW/FPGA implementation)
    * virtio device ID officially allocated
    * virtio spec has been submitted to virtio TC

Changes v4:
    * fixed spelling and formatting as pointed out by Randy
    * fixed virtio terminology: device/CPU instead of host/guest
    * spec: add clarification on versions and concurrency
    * driver: add endianess conversions
    * driver: rebased on mainline and fixed some little breaks
    * uapi: fixed device ID to now offically allocated: #41

Changes v3:
    * spec: fixed type names
    * spec: replace "host"/"guest" by "device"/"cpu"
    * spec: change terminology from "events" to "messages"
    * driver: fixed missing can_sleep flag
    * driver: select VIRTIO instead of depends on
    * driver: drop references to qemu in Kconfig
    * driver: fixed incomplete error handling and possible deadlock
              in case of sending buf failed
    * driver: dropped unneeded WARN_ON
    * driver: fixed retval of virtio_gpio_xmit()
    * driver: dynamically allocate virtio buffers
    * driver: added locking on gpio operations
    * driver: added irq_chip functions

Changes v2:
    * uapi: fixed header license
    * driver: sorted include's
    * driver: fixed formatting
    * driver: fixed unneeded devm allocation - plain kzalloc/kfree is enough
    * driver: fixed missing devm_kzalloc fail check
    * driver: use devm_kcalloc() for array allocation
    * spec: added virtio-gpio protocol specification
---
 Documentation/gpio/virtio-gpio.rst | 195 +++++++++++++++
 MAINTAINERS                        |   6 +
 drivers/gpio/Kconfig               |   7 +
 drivers/gpio/Makefile              |   1 +
 drivers/gpio/gpio-virtio.c         | 384 +++++++++++++++++++++++++++++
 include/uapi/linux/virtio_gpio.h   |  39 +++
 include/uapi/linux/virtio_ids.h    |   1 +
 7 files changed, 633 insertions(+)
 create mode 100644 Documentation/gpio/virtio-gpio.rst
 create mode 100644 drivers/gpio/gpio-virtio.c
 create mode 100644 include/uapi/linux/virtio_gpio.h

Comments

Linus Walleij June 16, 2021, 8:31 a.m. UTC | #1
Hi Enrico,

On Tue, Jun 15, 2021 at 7:49 PM Enrico Weigelt, metux IT consult
<info@metux.net> wrote:

> Introduce new GPIO driver for virtual GPIO devices via virtio.
>
> The driver implements the virtio-gpio protocol (ID 41), which can be
> used by either VM guests (e.g. bridging virtual gpios from the guest
> to real gpios in the host or attaching simulators for automatic
> application testing), as well as virtio-gpio hardware devices.
>
> Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>

So now there are two contesting patches for this and that creates a
social problem for us as maintainers. I am not too happy about that.

This situation activates the kernel management style document so
I advise involved parties to familiarize themselves with it:
https://www.kernel.org/doc/html/latest/process/management-style.html

Can we get the discussion down to actual technical points?
We really need a virtio GPIO driver, no doubt, so if everyone could
just work toward that goal and compromise with their specific pet
peeves that would be great.

Yours,
Linus Walleij
Viresh Kumar June 16, 2021, 11:49 a.m. UTC | #2
On 16-06-21, 10:31, Linus Walleij wrote:
> Hi Enrico,
> 
> On Tue, Jun 15, 2021 at 7:49 PM Enrico Weigelt, metux IT consult
> <info@metux.net> wrote:
> 
> > Introduce new GPIO driver for virtual GPIO devices via virtio.
> >
> > The driver implements the virtio-gpio protocol (ID 41), which can be
> > used by either VM guests (e.g. bridging virtual gpios from the guest
> > to real gpios in the host or attaching simulators for automatic
> > application testing), as well as virtio-gpio hardware devices.
> >
> > Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
> 
> So now there are two contesting patches for this and that creates a
> social problem for us as maintainers. I am not too happy about that.
> 
> This situation activates the kernel management style document so
> I advise involved parties to familiarize themselves with it:
> https://www.kernel.org/doc/html/latest/process/management-style.html
> 
> Can we get the discussion down to actual technical points?

+1

I can not agree more to this.

> We really need a virtio GPIO driver, no doubt, so if everyone could
> just work toward that goal and compromise with their specific pet
> peeves that would be great.

Enrico,

I am not looking to get any credits for the code or spec here. I don't
really care about that. For the very same reason I kept you as the
author of the 1st patch in the kernel series, so git keeps showing you
as the original author.

All I wanted to work on was the backend (in rust). This is what
happened for I2C for example, Jie Deng (Intel) worked on the spec and
Linux driver and I helped review it, make him fix a thing or two and
that's all. I worked on the rust implementation for the backend then.

You only ever sent 1 real versions of the Linux driver, that too
"6-months-back", there were no real blockers anywhere and you never
attempted to upstream anything.

Similarly, you "never" sent the specification properly to the virtio
lists for review. You sent it once as an attachment to an email, which
no one ever received.

When I tried to move this forward, invested a lot of time into making
it better from specification to code, reviews started happening, you
decided to start blocking it again.

You should be rather happy that something that you worked on is making
progress, specially when you didn't get time to do the same.

You wrote this in your patch:

> > Status:
> >     * this driver is now field tested for about 6 month
> >       (against KVM+Qemu as well as some HW/FPGA implementation)

Linux upstream doesn't really care about this, you can ask any Linux
Maintainer about this. If your code and specification isn't doing the
right thing, and isn't good enough, you will be asked to update it
upon reviews.

YOU JUST CAN'T SAY I WON'T because I have products based on this
version.

This is not how any open source project works. The code and
specification here doesn't belong to a single person or company. It is
for everyone's use.

> >     * virtio device ID officially allocated

Correct.

> >     * virtio spec has been submitted to virtio TC

Which specification are you talking about here ? The only
specification I can see on virtio lists is the one I sent.

And the driver you tried to send isn't aligned to that for sure, and
it takes us back from all the improvements I tried to do.

I am not saying that my version of the specification is the best and
there is no flaw in it. There surely is, but that can't be fixed by
sending another version of it. You need to make a technical point
about it and convince people that what you are saying is correct and
it is required for your use-case (not existing downstream solution).

There is no point going backwards now after making so much of
progress. Even if you try to send your version, it will slowly and
slowly reach very close to my latest version of code and spec. Because
your version of the code and spec weren't good enough for everyone. It
doesn't matter if you have real products on your earlier version, you
can keep using that in your downstream solution, but Linux kernel and
specification are going to get an improved version (from yours or
mine, but that doesn't matter here). You need to accept that changes
to that are inevitable since there are many users of gpio-virtio, not
just you and me, but many more (Like Bjorn expressed his interest in
this today for Qcom stuff).

Again, it would be better if you can discuss further on technical
merits or demerits in the currently circulated specification and give
your invaluable suggestions on the same.

Else we will end up spending few more months with just this and it
won't get us anywhere.

Thanks.
Enrico Weigelt, metux IT consult June 16, 2021, 2:41 p.m. UTC | #3
On 16.06.21 10:31, Linus Walleij wrote:
 > Hi Enrico,

 > So now there are two contesting patches for this and that creates a
 > social problem for us as maintainers. I am not too happy about that.

note that this is a polished up of a repost of my original driver
from last year.

 > Can we get the discussion down to actual technical points?

Sure. Perhaps you recall or discussions from late 2020. The missing
point there was (besides a few wording issues) the missing formal
specification process w/ virtio TC. (spec was already included in this
driver as well as the corresponding qemu patches).

My spec was not just meant for VM applications but also actual silicon
(as already mentioned, some folks of my client also implemented it in
FPGAs - don't ask me about details, they just mentioned it was quite
easy for them).

This is why it is so trimmed on things like fixed packet size,
unidirectional queues, mirroring packets w/ thus a few bits changed,
etc. In constrast, a more network-like approach might have been looking
nicer to traditional computer programmers, but much more complex to do
in pure logic and eat up *lots of* more gates (think of actual memory
management instead of hardwired latches, more complex decoding, etc).

Meanwhile it played out working nicely in several HIL installations

If I wanted to have a simple and CPU-only approach (just for VMs), I
would have just mounted some sysfs pieces via 9P :p

Several weeks ago, Viresh just wanted to continue the missing pieces
(which was: tex'ifying the spec and submitting to virtio TC), but then
unfortunately he invented something entirely different also put my name
on it.

Easy to imagine that I'm not amused at all.


--mtx
Enrico Weigelt, metux IT consult June 16, 2021, 3:04 p.m. UTC | #4
On 16.06.21 13:49, Viresh Kumar wrote:

> I am not looking to get any credits for the code or spec here. I don't
> really care about that. For the very same reason I kept you as the
> author of the 1st patch in the kernel series, so git keeps showing you
> as the original author.

Fine, and I'm not intenting to fight over credits. I'm just interested
in having a solid solution.

> All I wanted to work on was the backend (in rust). 

Okay, but why did you change the whole thing into something completely
different ?

> You only ever sent 1 real versions of the Linux driver, that too
> "6-months-back", there were no real blockers anywhere and you never
> attempted to upstream anything.

The backlog was in the maillist archive. It was just lingering because
of yet missing formal registering w/ vitio TC and I've been to busy with
more pressing tasks. (for example I've got keep public infrastructure
stuff up and running while folks are in lockdown).

> Similarly, you "never" sent the specification properly to the virtio
> lists for review. You sent it once as an attachment to an email, which
> no one ever received.

Half correct: I sent it to the list, but this wasn't tex'ified yet.

> When I tried to move this forward, invested a lot of time into making
> it better from specification to code, reviews started happening, you
> decided to start blocking it again.

When we had an email conversation about this, it was about submitting
the existing spec in a formal correct way. Don't get me wrong: I
apreciate that somebody's doing the beaurocratic work. But still have
no idea why you changed it completely, so there's quite nothing left
but the name and that it somehow does gpio via virtio.

> Linux upstream doesn't really care about this, you can ask any Linux
> Maintainer about this. 

I happen to be a maintainer myself, and we do actually care about
whether some thing is well tested.

> If your code and specification isn't doing the
> right thing, and isn't good enough, you will be asked to update it
> upon reviews.

Okay, please tell me, where exactly isn't right and why so.

> YOU JUST CAN'T SAY I WON'T because I have products based on this
> version.

Most of driver development goes pretty much like this. Yes, we would
prefer HW and FW vendors to talk with us first, but that rarely happens.

>>>      * virtio spec has been submitted to virtio TC
> 
> Which specification are you talking about here ? The only
> specification I can see on virtio lists is the one I sent.

The one I've resent (now texified) a few days ago. It had been submitted
in ascii form last year. The answer from virtio TC folks whas that there
are some formal steps to be done and it needs to be patched int their
tex document.

> And the driver you tried to send isn't aligned to that for sure, and
> it takes us back from all the improvements I tried to do.

Which improvements, exactly ? Unfortunately, you never talked to me
what exactly you've been missing.

I really have no idea, why you just

> I am not saying that my version of the specification is the best and
> there is no flaw in it. 

I did outline several problems of your spec on virtio list. Things that
already had already incorporated in my original one.

Really, I have no idea why you've never talked to me on specific issues,
but instead threw away, made something completely different and even
claim it would be just kinda "minor upgrade" of mine. WTF ?!

> There is no point going backwards now after making so much of
> progress. Even if you try to send your version, it will slowly and
> slowly reach very close to my latest version of code and spec. 

Or the other way round, as soon as silicon guys come in and see how
complicated and expensive your approach becomes.

> Because your version of the code and spec weren't good enough for everyone.

Again, please tell me what exactly was not "good enought" and who
exactly is "everyone".

> You need to accept that changes to that are inevitable since there 

You sound like a politician that tries to push an hidden agenda,
made by some secret interest group in the back room, against the
people - like "resistance is futile".


Finally, please tell me what exactly you're missing so hard in my spec,
that really needs a completely different implementation, which is hard
and expensive to implement in hardware.



--mtx
Enrico Weigelt, metux IT consult June 16, 2021, 6:47 p.m. UTC | #5
On 16.06.21 10:31, Linus Walleij wrote:

Hi folks,


<snip>

interesting: trying to post my tex'fied spec to virtio-dev and
virtio-comment quite some time now, but always being blocked. What's 
going on there ?


--mtx
Viresh Kumar June 17, 2021, 3:59 a.m. UTC | #6
On 16-06-21, 17:04, Enrico Weigelt, metux IT consult wrote:
> Half correct: I sent it to the list, but this wasn't tex'ified yet.
> 
> When we had an email conversation about this, it was about submitting
> the existing spec in a formal correct way. Don't get me wrong: I
> apreciate that somebody's doing the beaurocratic work. But still have
> no idea why you changed it completely, so there's quite nothing left
> but the name and that it somehow does gpio via virtio.

> The one I've resent (now texified) a few days ago. It had been submitted
> in ascii form last year. The answer from virtio TC folks whas that there
> are some formal steps to be done and it needs to be patched int their
> tex document.

Okay, we figured out now that you _haven't_ subscribed to virtio lists
and so your stuff never landed in anyone's inbox. But you did send
something and didn't completely went away.

Since you started this all and still want to do it, I will take my
patches back and let you finish with what you started. I will help
review them.

Please start with specification first, and resend them as soon as
possible. So we can start with reviews there.

Also please cc relevant people directly, like GPIO maintainers in
kernel and few more from CC list of this email, as most of these
people aren't subscribed to virtio lists, they will never get your
patches otherwise. Lets get over this once and for all.

> You sound like a politician that tries to push an hidden agenda,
> made by some secret interest group in the back room, against the
> people - like "resistance is futile".

:)
Enrico Weigelt, metux IT consult June 17, 2021, 9:54 a.m. UTC | #7
On 17.06.21 05:59, Viresh Kumar wrote:

 > Okay, we figured out now that you _haven't_ subscribed to virtio lists
 > and so your stuff never landed in anyone's inbox. But you did send
 > something and didn't completely went away.

Actually, I am subscribed in the list. We already had debates on it,
including on your postings (but also other things). And the ascii
version of the spec actually landed on the list last year, we had
discussions about it there.

I've just had the problem that my patches didn't go through, which is
very strange, since I actually am on the list and other mails of mine
went through all the time. I'm now suspecting it's triggered by some
subtle difference between my regular mail clients and git send-email.

 > Since you started this all and still want to do it, I will take my
 > patches back and let you finish with what you started. I will help
 > review them.

Thank you very much.

Please don't me wrong, I really don't wanna any kind of power play, just
wanna get an technically good solution. If there had been any mis-
understandings at that point, I'm officially saying sorry here.

Let's be friends.

You mentioned you've been missing with my spec. Please come foreward and
tell us what exactly you're missing and what your use cases are.

Note that I've intentionally left off certain "more sophisticated"
functionality we find on *some* gpio controllers, eg. per-line irq
masking, pinmux settings for several reasons, e.g.:

* those are only implemented by some hardware
* often implemented in or at least need to be coordinated with other
   pieces of hw (e.g. in SoCs, pinmux is usually done in a separate
   device)
* it shall be possible to support even the most simple devices and
   have the more sophisticated things totally optional. minium
   requirements for silicon implementations should be the lowest possible
   (IOW: minimal number of logic gates)

 >> You sound like a politician that tries to push an hidden agenda,
 >> made by some secret interest group in the back room, against the
 >> people - like "resistance is futile".
 >
 > :)

Perhaps I've been a bit overreacting at that point. But: this is really
that kind of talking we hear from politicians and corporate leaders
since many years, whenever they wanna push something through that we the
people don't want. Politicians use that as a social engineering tool for
demotivating any resistance. Over heare in Germany this even had become
a meme, and folks from CCC made a radio show about and named by that
(the German word is "alternativlos" - in english: without any
alternative). No idea about other countries, maybe it's a cultural
issue, but over here, those kind of talking had become a red light.

Of course, I never intended to accuse you of being one of these people.
Sorry if there's been misunderstanding.


Let's get back to your implementation: you've mentioned you're routing
raw virtio traffic into userland, to some other process (outside VMMs
like qemu) - how exactly are you doing that ?

That could be interesting for completely different scenarios. For
example, I'm currently exploring how to get VirGL running between 
separate processes running under the same kernel instance (fow now we
only have the driver side inside VM and the device outside it), means
driver and device are running as separate processes.

The primary use case are containers that shall have really GPU generic
drivers, not knowing anything about the actual hardware on the host.
Currently, container workloads wanting to use a GPU need to have special
drivers for exactly the HW the host happens to have. This makes generic,
portable container images a tuff problem.

I haven't digged deeply into the matter, but some virtio-tap transport
could be an relatively easy (probably not the most efficient) way to
solve this problem. In that scanario it would like this:

* we have a "virgl server" (could be some X or wayland application, or
   completely own compositor) opens up the device-end of an "virtio-tap"
   transport and attaches its virtio-gpio device emulation on it.
* "virtio-tap" now creates a driver-end, kernel probes an virtio-gpu
   instance on this (also leading to a new DRI device)
* container runtime picks the new DRI device and maps it into the
   container(s)
   [ yet open question, whether one DRI device for many containers
     is enough ]
* container application sees that virtio-gpu DRI device and speaks to
   it (mesa->virgl backend)
* the "virgl-server" receives buffers and commands from via virtio and
   sends them to the host's GL or Gallium API.

Once we're already there, we might think whether it could make sense
putting virtio routing into kvm itself, instead of letting qemu catch
page faults and virtual irqs. Yet have to see whether that's a good
idea, but I can imagine some performance improvements here.



--mtx
Viresh Kumar June 17, 2021, 11:47 a.m. UTC | #8
On 17-06-21, 11:54, Enrico Weigelt, metux IT consult wrote:
> Actually, I am subscribed in the list. We already had debates on it,
> including on your postings (but also other things).

Right.

> And the ascii
> version of the spec actually landed on the list last year, we had
> discussions about it there.

I tried to search for it earlier, but never found anything on virtio
list.  Maybe I missed it then.

> I've just had the problem that my patches didn't go through, which is
> very strange, since I actually am on the list and other mails of mine
> went through all the time. I'm now suspecting it's triggered by some
> subtle difference between my regular mail clients and git send-email.
> 
> > Since you started this all and still want to do it, I will take my
> > patches back and let you finish with what you started. I will help
> > review them.
> 
> Thank you very much.
> 
> Please don't me wrong, I really don't wanna any kind of power play, just
> wanna get an technically good solution. If there had been any mis-
> understandings at that point, I'm officially saying sorry here.

Its okay, we are both trying to make things better here :)

> Let's be friends.
> 
> You mentioned you've been missing with my spec. Please come foreward and
> tell us what exactly you're missing and what your use cases are.

I have sent a detailed review of your spec patch, lets do it there
point by point :)

> Note that I've intentionally left off certain "more sophisticated"
> functionality we find on *some* gpio controllers, eg. per-line irq
> masking, pinmux settings for several reasons, e.g.:
> 
> * those are only implemented by some hardware
> * often implemented in or at least need to be coordinated with other
>   pieces of hw (e.g. in SoCs, pinmux is usually done in a separate
>   device)
> * it shall be possible to support even the most simple devices and
>   have the more sophisticated things totally optional. minium
>   requirements for silicon implementations should be the lowest possible
>   (IOW: minimal number of logic gates)
> 
> >> You sound like a politician that tries to push an hidden agenda,
> >> made by some secret interest group in the back room, against the
> >> people - like "resistance is futile".
> >
> > :)
> 
> Perhaps I've been a bit overreacting at that point. But: this is really
> that kind of talking we hear from politicians and corporate leaders
> since many years, whenever they wanna push something through that we the
> people don't want. Politicians use that as a social engineering tool for
> demotivating any resistance. Over heare in Germany this even had become
> a meme, and folks from CCC made a radio show about and named by that
> (the German word is "alternativlos" - in english: without any
> alternative). No idea about other countries, maybe it's a cultural
> issue, but over here, those kind of talking had become a red light.
> 
> Of course, I never intended to accuse you of being one of these people.
> Sorry if there's been misunderstanding.

It sounded strange yesterday to be honest, but I have gone past it
already :)
 
> Let's get back to your implementation: you've mentioned you're routing
> raw virtio traffic into userland, to some other process (outside VMMs
> like qemu) - how exactly are you doing that ?
> 
> That could be interesting for completely different scenarios. For
> example, I'm currently exploring how to get VirGL running between separate
> processes running under the same kernel instance (fow now we
> only have the driver side inside VM and the device outside it), means
> driver and device are running as separate processes.
> 
> The primary use case are containers that shall have really GPU generic
> drivers, not knowing anything about the actual hardware on the host.
> Currently, container workloads wanting to use a GPU need to have special
> drivers for exactly the HW the host happens to have. This makes generic,
> portable container images a tuff problem.
> 
> I haven't digged deeply into the matter, but some virtio-tap transport
> could be an relatively easy (probably not the most efficient) way to
> solve this problem. In that scanario it would like this:
> 
> * we have a "virgl server" (could be some X or wayland application, or
>   completely own compositor) opens up the device-end of an "virtio-tap"
>   transport and attaches its virtio-gpio device emulation on it.
> * "virtio-tap" now creates a driver-end, kernel probes an virtio-gpu
>   instance on this (also leading to a new DRI device)
> * container runtime picks the new DRI device and maps it into the
>   container(s)
>   [ yet open question, whether one DRI device for many containers
>     is enough ]
> * container application sees that virtio-gpu DRI device and speaks to
>   it (mesa->virgl backend)
> * the "virgl-server" receives buffers and commands from via virtio and
>   sends them to the host's GL or Gallium API.
> 
> Once we're already there, we might think whether it could make sense
> putting virtio routing into kvm itself, instead of letting qemu catch
> page faults and virtual irqs. Yet have to see whether that's a good
> idea, but I can imagine some performance improvements here.

We (at Linaro) work on software enablement normally and not end
products (rarely that happen though), like framework level work in the
kernel which can later be used by everyone to build their drivers on.

There are many companies like Qualcomm, ST Micro, etc, who want to use
Virtio in general for Automotive or other applications / solution. The
purpose of Project Stratos [1], an initiative of Linaro, is working
towards developing hypervisor agnostic Virtio interfaces and
standards. The end products and applications will be worked on by the
members directly and we need to add basic minimum support, with all
the generally required APIs or interfaces.
diff mbox series

Patch

diff --git a/Documentation/gpio/virtio-gpio.rst b/Documentation/gpio/virtio-gpio.rst
new file mode 100644
index 000000000000..5fcc93f51174
--- /dev/null
+++ b/Documentation/gpio/virtio-gpio.rst
@@ -0,0 +1,195 @@ 
+===================
+Virtio-GPIO protocol specification
+===================
+...........
+Specification for virtio-based GPIO devices
+...........
+
++------------
++Version_ 1.0
++------------
+
+General
+===================
+
+The virtio-gpio protocol provides access to general purpose IO devices via
+virtio interfaces, used by many virtual machine monitors as well as hardware
+fabrics. In VM setups, these GPIOs could be either provided by some simulator
+(e.g. virtual HIL), routed to some external device or routed to real GPIOs on
+the host (e.g. virtualized embedded applications).
+
+Instead of simulating some existing real GPIO chip within an VMM, this
+protocol provides a hardware independent interface between CPU and device
+that solely relies on an active virtio connection (no matter which transport
+actually used), no other buses or additional platform driver logic required.
+
+At the same time, this protocol be implemented directly in virtio attached
+hardware, FPGAs or tiny MCUs.
+
+Protocol layout
+===================
+
+Configuration space
+----------------------
+
++--------+----------+-------------------------------+
+| Offset | Type     | Description                   |
++========+==========+===============================+
+| 0x00   | u8       | version                       |
++--------+----------+-------------------------------+
+| 0x02   | u16      | number of GPIO lines          |
++--------+----------+-------------------------------+
+| 0x04   | u32      | size of gpio name block       |
++--------+----------+-------------------------------+
+| 0x20   | char[32] | device name (0-terminated)    |
++--------+----------+-------------------------------+
+| 0x40   | char[]   | line names block              |
++--------+----------+-------------------------------+
+
+- for version field currently only value 1 supported.
+- the line names block holds a stream of zero-terminated strings,
+  containing the individual line names in ASCII. line names must unique.
+- unspecified fields are reserved for future use and should be zero.
+
+Virtqueues and messages:
+------------------------
+
+- Queue #0: transmission from device to CPU
+- Queue #1: transmission from CPU to device
+
+The queues transport messages of the struct virtio_gpio_msg:
+
+Message format:
+~~~~~~~~~~~~~~~
+
++--------+----------+---------------+
+| Offset | Type     | Description   |
++========+==========+===============+
+| 0x00   | uint16   | message type  |
++--------+----------+---------------+
+| 0x02   | uint16   | line id       |
++--------+----------+---------------+
+| 0x04   | uint32   | value         |
++--------+----------+---------------+
+
+Message types:
+~~~~~~~~~~~~~~
+
++---------+----------------------------------------+-----------------------------+
+| Code    | Symbol                                 |                             |
++=========+========================================+=============================+
+| 0x0001  | VIRTIO_GPIO_MSG_CPU_REQUEST            | request gpio line           |
++---------+----------------------------------------+-----------------------------+
+| 0x0002  | VIRTIO_GPIO_MSG_CPU_DIRECTION_INPUT    | set direction to input      |
++---------+----------------------------------------+-----------------------------+
+| 0x0003  | VIRTIO_GPIO_MSG_CPU_DIRECTION_OUTPUT   | set direction to output     |
++---------+----------------------------------------+-----------------------------+
+| 0x0004  | VIRTIO_GPIO_MSG_CPU_GET_DIRECTION      | read current direction      |
++---------+----------------------------------------+-----------------------------+
+| 0x0005  | VIRTIO_GPIO_MSG_CPU_GET_LEVEL          | read current level          |
++---------+----------------------------------------+-----------------------------+
+| 0x0006  | VIRTIO_GPIO_MSG_CPU_SET_LEVEL          | set current (out) level     |
++---------+----------------------------------------+-----------------------------+
+| 0x0011  | VIRTIO_GPIO_MSG_DEVICE_LEVEL           | state changed (device->CPU) |
++---------+----------------------------------------+-----------------------------+
+| 0x8000  | VIRTIO_GPIO_MSG_REPLY                  | device reply mask           |
++---------+----------------------------------------+-----------------------------+
+
+Data flow:
+----------------------
+
+- all operations, except ``VIRTIO_GPIO_MSG_DEVICE_LEVEL``, are initiated by CPU
+- device replies with the orinal ``type`` value OR'ed with ``VIRTIO_GPIO_MSG_REPLY``
+- ``VIRTIO_GPIO_MSG_DEVICE_LEVEL`` is only sent asynchronously from device to CPU
+- in replies, a negative ``value`` field denotes an Unix-style / POSIX errno code
+- valid direction values are:
+  * 0 = output
+  * 1 = input
+- valid line state values are:
+  * 0 = inactive
+  * 1 = active
+
+VIRTIO_GPIO_MSG_CPU_REQUEST
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- notify the device that given line# is going to be used
+- request:
+  * ``line`` field: line number
+  * ``value`` field: unused
+- reply:
+  * ``value`` field: errno code (0 = success)
+
+VIRTIO_GPIO_MSG_CPU_DIRECTION_INPUT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- set line line direction to input
+- request:
+  * ``line`` field: line number
+  * ``value`` field: unused
+- reply: value field holds errno
+  * ``value`` field: errno code (0 = success)
+
+VIRTIO_GPIO_MSG_CPU_DIRECTION_OUTPUT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- set line direction to output and given line state
+- request:
+  * ``line`` field: line number
+  * ``value`` field: output state (0=inactive, 1=active)
+- reply:
+  * ``value`` field: holds errno
+
+VIRTIO_GPIO_MSG_CPU_GET_DIRECTION
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- retrieve line direction
+- request:
+  * ``line`` field: line number
+  * ``value`` field: unused
+- reply:
+  * ``value`` field: direction (0=output, 1=input) or errno code
+
+VIRTIO_GPIO_MSG_CPU_GET_LEVEL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- retrieve line state value
+- request:
+  * ``line`` field: line number
+  * ``value`` field: unused
+- reply:
+  * ``value`` field: line state (0=inactive, 1=active) or errno code
+
+VIRTIO_GPIO_MSG_CPU_SET_LEVEL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- set line state value (output only)
+- request:
+  * ``line`` field: line number
+  * ``value`` field: line state (0=inactive, 1=active)
+- reply:
+  * ``value`` field: new line state or errno code
+
+VIRTIO_GPIO_MSG_DEVICE_LEVEL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- async notification from device to CPU: line state changed
+- ``line`` field: line number
+- ``value`` field: new line state (0=inactive, 1=active)
+
+Request concurrency
+===================
+
+- CPU may send multiple request in serial, as long as the virtio queue
+  is not exceeded
+- device replies must be sent in the same order than the CPU requests
+- CPU should process asynchronous messages from device as soon as possible,
+  in order to avoid missing messages due to queue overrun
+
+Future versions
+===================
+
+- future versions must increment the ``version`` value
+- the basic data structures (config space, message format) should remain
+  backwards compatible, but may increased in size or use reserved fields
+- device needs to support commands in older versions
+- CPU should not send commands of newer versions that the device doesn't support
diff --git a/MAINTAINERS b/MAINTAINERS
index bc0ceef87b73..1189ae5b442b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19397,6 +19397,12 @@  F:	Documentation/filesystems/virtiofs.rst
 F:	fs/fuse/virtio_fs.c
 F:	include/uapi/linux/virtio_fs.h
 
+VIRTIO GPIO DRIVER
+M:	Enrico Weigelt, metux IT consult <info@metux.net>
+S:	Maintained
+F:	drivers/gpio/gpio-virtio.c
+F:	include/uapi/linux/virtio_gpio.h
+
 VIRTIO GPU DRIVER
 M:	David Airlie <airlied@linux.ie>
 M:	Gerd Hoffmann <kraxel@redhat.com>
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 1dd0ec6727fd..b9871e5b3c74 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1655,6 +1655,13 @@  config GPIO_MOCKUP
 	  tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
 	  it.
 
+config GPIO_VIRTIO
+	tristate "VirtIO GPIO support"
+	select VIRTIO
+	select GPIOLIB_IRQCHIP
+	help
+	  Say Y here to enable guest support for virtio-based GPIOs.
+
 endmenu
 
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d7c81e1611a4..ba42e6549c87 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -162,6 +162,7 @@  obj-$(CONFIG_GPIO_TWL4030)		+= gpio-twl4030.o
 obj-$(CONFIG_GPIO_TWL6040)		+= gpio-twl6040.o
 obj-$(CONFIG_GPIO_UCB1400)		+= gpio-ucb1400.o
 obj-$(CONFIG_GPIO_UNIPHIER)		+= gpio-uniphier.o
+obj-$(CONFIG_GPIO_VIRTIO)		+= gpio-virtio.o
 obj-$(CONFIG_GPIO_VF610)		+= gpio-vf610.o
 obj-$(CONFIG_GPIO_VIPERBOARD)		+= gpio-viperboard.o
 obj-$(CONFIG_GPIO_VISCONTI)		+= gpio-visconti.o
diff --git a/drivers/gpio/gpio-virtio.c b/drivers/gpio/gpio-virtio.c
new file mode 100644
index 000000000000..4938cd0350ff
--- /dev/null
+++ b/drivers/gpio/gpio-virtio.c
@@ -0,0 +1,384 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * GPIO driver for virtio-based virtual GPIOs
+ *
+ * Copyright (C) 2018 metux IT consult
+ * Author: Enrico Weigelt, metux IT consult <info@metux.net>
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/virtio_config.h>
+#include <uapi/linux/virtio_ids.h>
+#include <uapi/linux/virtio_gpio.h>
+
+#define CONFIG_VIRTIO_GPIO_MAX_IRQ		256
+
+#define MSG_BUF_SZ	(sizeof(struct virtio_gpio_msg))
+
+struct virtio_gpio_priv {
+	struct gpio_chip gc;
+	spinlock_t vq_lock;
+	struct virtio_device *vdev;
+	int num_gpios;
+	char *name;
+	struct virtqueue *vq_rx;
+	struct virtqueue *vq_tx;
+	struct virtio_gpio_msg last;
+	wait_queue_head_t waitq;
+	unsigned long reply_wait;
+	struct irq_chip irq_chip;
+	DECLARE_BITMAP(irq_mask, CONFIG_VIRTIO_GPIO_MAX_IRQ);
+	unsigned int irq_parents;
+	struct mutex rpc_mutex;
+};
+
+static int virtio_gpio_prepare_inbuf(struct virtio_gpio_priv *priv)
+{
+	struct scatterlist rcv_sg;
+	struct virtio_gpio_msg *buf;
+
+	buf = devm_kzalloc(&priv->vdev->dev, MSG_BUF_SZ, GFP_KERNEL);
+	if (!buf) {
+		dev_err(&priv->vdev->dev, "failed to allocate input buffer\n");
+		return -ENOMEM;
+	}
+
+	sg_init_one(&rcv_sg, buf, sizeof(struct virtio_gpio_priv));
+	virtqueue_add_inbuf(priv->vq_rx, &rcv_sg, 1, buf, GFP_KERNEL);
+	virtqueue_kick(priv->vq_rx);
+
+	return 0;
+}
+
+static int virtio_gpio_xmit(struct virtio_gpio_priv *priv, int type,
+			    int pin, int value, struct virtio_gpio_msg *ev)
+{
+	struct scatterlist xmit_sg;
+	int ret;
+	unsigned long flags;
+
+	ev->type = cpu_to_le16(type);
+	ev->pin = cpu_to_le16(pin);
+	ev->value = cpu_to_le32(value);
+
+	sg_init_one(&xmit_sg, ev, MSG_BUF_SZ);
+	spin_lock_irqsave(&priv->vq_lock, flags);
+	ret = virtqueue_add_outbuf(priv->vq_tx, &xmit_sg, 1, priv, GFP_KERNEL);
+	if (ret < 0) {
+		dev_err(&priv->vdev->dev,
+			"virtqueue_add_outbuf() failed: %d\n", ret);
+		goto out;
+	}
+	virtqueue_kick(priv->vq_tx);
+
+out:
+	spin_unlock_irqrestore(&priv->vq_lock, flags);
+	return ret;
+}
+
+static inline void wakeup_event(struct virtio_gpio_priv *priv, int id)
+{
+	set_bit(id, &priv->reply_wait);
+}
+
+static inline int check_event(struct virtio_gpio_priv *priv, int id)
+{
+	return test_bit(id, &priv->reply_wait);
+}
+
+static inline void clear_event(struct virtio_gpio_priv *priv, int id)
+{
+	clear_bit(id, &priv->reply_wait);
+}
+
+static int virtio_gpio_rpc(struct virtio_gpio_priv *priv, int type,
+			   int pin, int value)
+{
+	int ret;
+	struct virtio_gpio_msg *buf = kzalloc(MSG_BUF_SZ, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	mutex_lock(&priv->rpc_mutex);
+	virtio_gpio_prepare_inbuf(priv);
+	clear_event(priv, type);
+
+	ret = virtio_gpio_xmit(priv, type, pin, value, buf);
+	if (ret)
+		goto out;
+
+	wait_event_interruptible(priv->waitq, check_event(priv, type));
+	ret = priv->last.value;
+
+out:
+	mutex_unlock(&priv->rpc_mutex);
+	kfree(buf);
+	return ret;
+}
+
+static int virtio_gpio_direction_input(struct gpio_chip *gc,
+				       unsigned int pin)
+{
+	return virtio_gpio_rpc(gpiochip_get_data(gc),
+			       VIRTIO_GPIO_MSG_CPU_DIRECTION_INPUT,
+			       pin, 0);
+}
+
+static int virtio_gpio_direction_output(struct gpio_chip *gc,
+					unsigned int pin, int value)
+{
+	return virtio_gpio_rpc(gpiochip_get_data(gc),
+			       VIRTIO_GPIO_MSG_CPU_DIRECTION_OUTPUT,
+			       pin, value);
+}
+
+static int virtio_gpio_get_direction(struct gpio_chip *gc, unsigned int pin)
+{
+	return virtio_gpio_rpc(gpiochip_get_data(gc),
+			       VIRTIO_GPIO_MSG_CPU_GET_DIRECTION,
+			       pin, 0);
+}
+
+static void virtio_gpio_set(struct gpio_chip *gc,
+			    unsigned int pin, int value)
+{
+	virtio_gpio_rpc(gpiochip_get_data(gc),
+			VIRTIO_GPIO_MSG_CPU_SET_LEVEL, pin, value);
+}
+
+static int virtio_gpio_get(struct gpio_chip *gc,
+			   unsigned int pin)
+{
+	return virtio_gpio_rpc(gpiochip_get_data(gc),
+			       VIRTIO_GPIO_MSG_CPU_GET_LEVEL, pin, 0);
+}
+
+static int virtio_gpio_request(struct gpio_chip *gc,
+			       unsigned int pin)
+{
+	return virtio_gpio_rpc(gpiochip_get_data(gc),
+			       VIRTIO_GPIO_MSG_CPU_REQUEST, pin, 0);
+}
+
+static void virtio_gpio_signal(struct virtio_gpio_priv *priv, int event,
+			       int pin, int value)
+{
+	int mapped_irq = irq_find_mapping(priv->gc.irq.domain, pin);
+
+	if ((pin < priv->num_gpios) && test_bit(pin, priv->irq_mask))
+		generic_handle_irq(mapped_irq);
+}
+
+static void virtio_gpio_data_rx(struct virtqueue *vq)
+{
+	struct virtio_gpio_priv *priv = vq->vdev->priv;
+	void *data;
+	unsigned int len;
+	struct virtio_gpio_msg *ev;
+
+	data = virtqueue_get_buf(priv->vq_rx, &len);
+	if (!data || !len) {
+		dev_warn(&vq->vdev->dev, "RX received no data ! %d\n", len);
+		return;
+	}
+
+	ev = data;
+
+	memcpy(&priv->last, data, MSG_BUF_SZ);
+
+	ev->type  = le16_to_cpu(ev->type);
+	ev->pin   = le16_to_cpu(ev->pin);
+	ev->value = le32_to_cpu(ev->value);
+
+	switch (ev->type) {
+	case VIRTIO_GPIO_MSG_DEVICE_LEVEL:
+		virtio_gpio_prepare_inbuf(priv);
+		virtio_gpio_signal(priv, ev->type, ev->pin, ev->value);
+		break;
+	default:
+		wakeup_event(priv, ev->type & ~VIRTIO_GPIO_MSG_REPLY);
+		break;
+	}
+
+	wake_up_all(&priv->waitq);
+
+	devm_kfree(&priv->vdev->dev, data);
+}
+
+static int virtio_gpio_alloc_vq(struct virtio_gpio_priv *priv)
+{
+	struct virtqueue *vqs[2];
+	vq_callback_t *cbs[] = {
+		NULL,
+		virtio_gpio_data_rx,
+	};
+	static const char * const names[] = { "in", "out", };
+	int ret;
+
+	ret = virtio_find_vqs(priv->vdev, 2, vqs, cbs, names, NULL);
+	if (ret) {
+		dev_err(&priv->vdev->dev, "failed to alloc vqs: %d\n", ret);
+		return ret;
+	}
+
+	priv->vq_rx = vqs[0];
+	priv->vq_tx = vqs[1];
+
+	ret = virtio_gpio_prepare_inbuf(priv);
+	if (ret) {
+		dev_err(&priv->vdev->dev, "preparing inbuf failed\n");
+		return ret;
+	}
+
+	virtqueue_enable_cb(priv->vq_rx);
+	virtio_device_ready(priv->vdev);
+
+	return 0;
+}
+
+static void virtio_gpio_irq_unmask(struct irq_data *irq)
+{
+	int hwirq = irqd_to_hwirq(irq);
+	struct virtio_gpio_priv *priv
+		= gpiochip_get_data(irq_data_get_irq_chip_data(irq));
+	if (hwirq < CONFIG_VIRTIO_GPIO_MAX_IRQ)
+		set_bit(hwirq, priv->irq_mask);
+}
+
+static void virtio_gpio_irq_mask(struct irq_data *irq)
+{
+	int hwirq = irqd_to_hwirq(irq);
+	struct virtio_gpio_priv *priv
+		= gpiochip_get_data(irq_data_get_irq_chip_data(irq));
+	if (hwirq < CONFIG_VIRTIO_GPIO_MAX_IRQ)
+		clear_bit(hwirq, priv->irq_mask);
+}
+
+static int virtio_gpio_probe(struct virtio_device *vdev)
+{
+	struct virtio_gpio_priv *priv;
+	struct virtio_gpio_config cf = {};
+	char *name_buffer;
+	const char **gpio_names = NULL;
+	struct device *dev = &vdev->dev;
+	struct gpio_irq_chip *girq;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->name = devm_kzalloc(dev, sizeof(cf.name)+1, GFP_KERNEL);
+	if (!priv->name)
+		return -ENOMEM;
+
+	spin_lock_init(&priv->vq_lock);
+	mutex_init(&priv->rpc_mutex);
+
+	virtio_cread_le(vdev, struct virtio_gpio_config, version, &cf.version);
+	virtio_cread_le(vdev, struct virtio_gpio_config, num_gpios,
+			&cf.num_gpios);
+	virtio_cread_le(vdev, struct virtio_gpio_config, names_size,
+			&cf.names_size);
+	virtio_cread_bytes(vdev, offsetof(struct virtio_gpio_config, name),
+			   priv->name, sizeof(cf.name));
+
+	if (cf.version != 1) {
+		dev_err(dev, "unsupported interface version %d\n", cf.version);
+		return -EINVAL;
+	}
+
+	priv->num_gpios = cf.num_gpios;
+
+	if (cf.names_size) {
+		char *bufwalk;
+		int idx = 0;
+
+		name_buffer = devm_kzalloc(&vdev->dev, cf.names_size,
+					   GFP_KERNEL)+1;
+		virtio_cread_bytes(vdev, sizeof(struct virtio_gpio_config),
+				   name_buffer, cf.names_size);
+		name_buffer[cf.names_size] = 0;
+
+		gpio_names = devm_kcalloc(dev, priv->num_gpios, sizeof(char *),
+					  GFP_KERNEL);
+		bufwalk = name_buffer;
+
+		while (idx < priv->num_gpios &&
+		       bufwalk < (name_buffer+cf.names_size)) {
+			gpio_names[idx] = (strlen(bufwalk) ? bufwalk : NULL);
+			bufwalk += strlen(bufwalk)+1;
+			idx++;
+		}
+	}
+
+	priv->vdev			= vdev;
+	vdev->priv = priv;
+
+	priv->gc.owner			= THIS_MODULE;
+	priv->gc.parent			= dev;
+	priv->gc.label			= (priv->name[0] ? priv->name
+							 : dev_name(dev));
+	priv->gc.ngpio			= priv->num_gpios;
+	priv->gc.names			= gpio_names;
+	priv->gc.base			= -1;
+	priv->gc.request		= virtio_gpio_request;
+	priv->gc.direction_input	= virtio_gpio_direction_input;
+	priv->gc.direction_output	= virtio_gpio_direction_output;
+	priv->gc.get_direction		= virtio_gpio_get_direction;
+	priv->gc.get			= virtio_gpio_get;
+	priv->gc.set			= virtio_gpio_set;
+	priv->gc.can_sleep		= true;
+
+	priv->irq_chip.name		= "virtio-gpio-irq";
+	priv->irq_chip.irq_mask		= virtio_gpio_irq_mask;
+	priv->irq_chip.irq_unmask	= virtio_gpio_irq_unmask;
+
+	girq = &priv->gc.irq;
+
+	priv->gc.irq.chip		= &priv->irq_chip;
+	priv->gc.irq.num_parents	= 1;
+	priv->gc.irq.default_type	= IRQ_TYPE_NONE;
+	priv->gc.irq.handler		= handle_simple_irq;
+	priv->gc.irq.parents		= &priv->irq_parents;
+	priv->irq_parents		= 0;
+
+	init_waitqueue_head(&priv->waitq);
+
+	priv->reply_wait = 0;
+
+	virtio_gpio_alloc_vq(priv);
+
+	return devm_gpiochip_add_data(dev, &priv->gc, priv);
+}
+
+static void virtio_gpio_remove(struct virtio_device *vdev)
+{
+	/* just dummy, virtio subsys can't cope w/ NULL vector */
+}
+
+static const struct virtio_device_id id_table[] = {
+	{ VIRTIO_ID_GPIO, VIRTIO_DEV_ANY_ID },
+	{ 0 },
+};
+
+static struct virtio_driver virtio_gpio_driver = {
+	.driver.name	= KBUILD_MODNAME,
+	.driver.owner	= THIS_MODULE,
+	.id_table	= id_table,
+	.probe		= virtio_gpio_probe,
+	.remove		= virtio_gpio_remove,
+};
+
+module_virtio_driver(virtio_gpio_driver);
+
+MODULE_AUTHOR("Enrico Weigelt, metux IT consult <info@metux.net>");
+MODULE_DESCRIPTION("VirtIO GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/virtio_gpio.h b/include/uapi/linux/virtio_gpio.h
new file mode 100644
index 000000000000..5b90acae6c85
--- /dev/null
+++ b/include/uapi/linux/virtio_gpio.h
@@ -0,0 +1,39 @@ 
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _LINUX_VIRTIO_GPIO_H
+#define _LINUX_VIRTIO_GPIO_H
+
+#include <linux/types.h>
+
+enum virtio_gpio_msg_type {
+	// requests from cpu to device
+	VIRTIO_GPIO_MSG_CPU_REQUEST		= 0x01,
+	VIRTIO_GPIO_MSG_CPU_DIRECTION_INPUT	= 0x02,
+	VIRTIO_GPIO_MSG_CPU_DIRECTION_OUTPUT	= 0x03,
+	VIRTIO_GPIO_MSG_CPU_GET_DIRECTION	= 0x04,
+	VIRTIO_GPIO_MSG_CPU_GET_LEVEL		= 0x05,
+	VIRTIO_GPIO_MSG_CPU_SET_LEVEL		= 0x06,
+
+	// messages from host to guest
+	VIRTIO_GPIO_MSG_DEVICE_LEVEL		= 0x11,	// gpio state changed
+
+	/* mask bit set on host->guest reply */
+	VIRTIO_GPIO_MSG_REPLY			= 0x8000,
+};
+
+struct virtio_gpio_config {
+	__u8    version;
+	__u8    reserved0;
+	__u16   num_gpios;
+	__u32   names_size;
+	__u8    reserved1[24];
+	__u8    name[32];
+};
+
+struct virtio_gpio_msg {
+	__le16 type;
+	__le16 pin;
+	__le32 value;
+};
+
+#endif /* _LINUX_VIRTIO_GPIO_H */
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index 4fe842c3a3a9..0c9bac389ce0 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -56,5 +56,6 @@ 
 #define VIRTIO_ID_PMEM			27 /* virtio pmem */
 #define VIRTIO_ID_MAC80211_HWSIM	29 /* virtio mac80211-hwsim */
 #define VIRTIO_ID_BT			40 /* virtio bluetooth */
+#define VIRTIO_ID_GPIO			41 /* virtio GPIO */
 
 #endif /* _LINUX_VIRTIO_IDS_H */