OSDN Git Service

Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Apr 2015 17:55:06 +0000 (10:55 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Apr 2015 17:55:06 +0000 (10:55 -0700)
Pull virtio updates from Rusty Russell:
 "Some virtio internal cleanups, a new virtio device "virtio input", and
  a change to allow the legacy virtio balloon.

  Most excitingly, some lguest work! No seriously, I got some cleanup
  patches"

* tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
  virtio: drop virtio_device_is_legacy_only
  virtio_pci: support non-legacy balloon devices
  virtio_mmio: support non-legacy balloon devices
  virtio_ccw: support non-legacy balloon devices
  virtio: balloon might not be a legacy device
  virtio_balloon: transitional interface
  virtio_ring: Update weak barriers to use dma_wmb/rmb
  virtio_pci_modern: switch to type-safe io accessors
  virtio_pci_modern: type-safe io accessors
  lguest: handle traps on the "interrupt suppressed" iret instruction.
  virtio: drop a useless config read
  virtio_config: reorder functions
  Add virtio-input driver.
  lguest: suppress interrupts for single insn, not range.
  lguest: simplify lguest_iret
  lguest: rename i386_head.S in the comments
  lguest: explicitly set miscdevice's private_data NULL
  lguest: fix pending interrupt test.

24 files changed:
MAINTAINERS
arch/x86/include/asm/lguest.h
arch/x86/lguest/boot.c
arch/x86/lguest/head_32.S
drivers/lguest/hypercalls.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/lg.h
drivers/lguest/lguest_user.c
drivers/s390/kvm/virtio_ccw.c
drivers/virtio/Kconfig
drivers/virtio/Makefile
drivers/virtio/virtio.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_input.c [new file with mode: 0644]
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci_modern.c
include/linux/lguest.h
include/linux/virtio.h
include/linux/virtio_config.h
include/linux/virtio_ring.h
include/uapi/linux/Kbuild
include/uapi/linux/virtio_balloon.h
include/uapi/linux/virtio_ids.h
include/uapi/linux/virtio_input.h [new file with mode: 0644]

index f6f5950..df536b1 100644 (file)
@@ -10517,6 +10517,12 @@ S:     Maintained
 F:     drivers/vhost/
 F:     include/uapi/linux/vhost.h
 
+VIRTIO INPUT DRIVER
+M:     Gerd Hoffmann <kraxel@redhat.com>
+S:     Maintained
+F:     drivers/virtio/virtio_input.c
+F:     include/uapi/linux/virtio_input.h
+
 VIA RHINE NETWORK DRIVER
 M:     Roger Luethi <rl@hellgate.ch>
 S:     Maintained
index e2d4a4a..3bbc07a 100644 (file)
@@ -20,13 +20,10 @@ extern unsigned long switcher_addr;
 /* Found in switcher.S */
 extern unsigned long default_idt_entries[];
 
-/* Declarations for definitions in lguest_guest.S */
-extern char lguest_noirq_start[], lguest_noirq_end[];
+/* Declarations for definitions in arch/x86/lguest/head_32.S */
+extern char lguest_noirq_iret[];
 extern const char lgstart_cli[], lgend_cli[];
-extern const char lgstart_sti[], lgend_sti[];
-extern const char lgstart_popf[], lgend_popf[];
 extern const char lgstart_pushf[], lgend_pushf[];
-extern const char lgstart_iret[], lgend_iret[];
 
 extern void lguest_iret(void);
 extern void lguest_init(void);
index 717908b..8f9a133 100644 (file)
@@ -87,8 +87,7 @@
 
 struct lguest_data lguest_data = {
        .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
-       .noirq_start = (u32)lguest_noirq_start,
-       .noirq_end = (u32)lguest_noirq_end,
+       .noirq_iret = (u32)lguest_noirq_iret,
        .kernel_address = PAGE_OFFSET,
        .blocked_interrupts = { 1 }, /* Block timer interrupts */
        .syscall_vec = SYSCALL_VECTOR,
@@ -262,7 +261,7 @@ PV_CALLEE_SAVE_REGS_THUNK(lguest_save_fl);
 PV_CALLEE_SAVE_REGS_THUNK(lguest_irq_disable);
 /*:*/
 
-/* These are in i386_head.S */
+/* These are in head_32.S */
 extern void lg_irq_enable(void);
 extern void lg_restore_fl(unsigned long flags);
 
@@ -1368,7 +1367,7 @@ static void lguest_restart(char *reason)
  * fit comfortably.
  *
  * First we need assembly templates of each of the patchable Guest operations,
- * and these are in i386_head.S.
+ * and these are in head_32.S.
  */
 
 /*G:060 We construct a table from the assembler templates: */
index 6ddfe4f..d5ae63f 100644 (file)
@@ -84,7 +84,7 @@ ENTRY(lg_irq_enable)
         * set lguest_data.irq_pending to X86_EFLAGS_IF.  If it's not zero, we
         * jump to send_interrupts, otherwise we're done.
         */
-       testl $0, lguest_data+LGUEST_DATA_irq_pending
+       cmpl $0, lguest_data+LGUEST_DATA_irq_pending
        jnz send_interrupts
        /*
         * One cool thing about x86 is that you can do many things without using
@@ -133,9 +133,8 @@ ENTRY(lg_restore_fl)
        ret
 /*:*/
 
-/* These demark the EIP range where host should never deliver interrupts. */
-.global lguest_noirq_start
-.global lguest_noirq_end
+/* These demark the EIP where host should never deliver interrupts. */
+.global lguest_noirq_iret
 
 /*M:004
  * When the Host reflects a trap or injects an interrupt into the Guest, it
@@ -168,29 +167,26 @@ ENTRY(lg_restore_fl)
  * So we have to copy eflags from the stack to lguest_data.irq_enabled before
  * we do the "iret".
  *
- * There are two problems with this: firstly, we need to use a register to do
- * the copy and secondly, the whole thing needs to be atomic.  The first
- * problem is easy to solve: push %eax on the stack so we can use it, and then
- * restore it at the end just before the real "iret".
+ * There are two problems with this: firstly, we can't clobber any registers
+ * and secondly, the whole thing needs to be atomic.  The first problem
+ * is solved by using "push memory"/"pop memory" instruction pair for copying.
  *
  * The second is harder: copying eflags to lguest_data.irq_enabled will turn
  * interrupts on before we're finished, so we could be interrupted before we
- * return to userspace or wherever.  Our solution to this is to surround the
- * code with lguest_noirq_start: and lguest_noirq_end: labels.  We tell the
+ * return to userspace or wherever.  Our solution to this is to tell the
  * Host that it is *never* to interrupt us there, even if interrupts seem to be
- * enabled.
+ * enabled. (It's not necessary to protect pop instruction, since
+ * data gets updated only after it completes, so we only need to protect
+ * one instruction, iret).
  */
 ENTRY(lguest_iret)
-       pushl   %eax
-       movl    12(%esp), %eax
-lguest_noirq_start:
+       pushl   2*4(%esp)
        /*
         * Note the %ss: segment prefix here.  Normal data accesses use the
         * "ds" segment, but that will have already been restored for whatever
         * we're returning to (such as userspace): we can't trust it.  The %ss:
         * prefix makes sure we use the stack segment, which is still valid.
         */
-       movl    %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled
-       popl    %eax
+       popl    %ss:lguest_data+LGUEST_DATA_irq_enabled
+lguest_noirq_iret:
        iret
-lguest_noirq_end:
index 1219af4..19a3228 100644 (file)
@@ -211,10 +211,9 @@ static void initialize(struct lg_cpu *cpu)
 
        /*
         * The Guest tells us where we're not to deliver interrupts by putting
-        * the range of addresses into "struct lguest_data".
+        * the instruction address into "struct lguest_data".
         */
-       if (get_user(cpu->lg->noirq_start, &cpu->lg->lguest_data->noirq_start)
-           || get_user(cpu->lg->noirq_end, &cpu->lg->lguest_data->noirq_end))
+       if (get_user(cpu->lg->noirq_iret, &cpu->lg->lguest_data->noirq_iret))
                kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
 
        /*
index 70dfcdc..5e7559b 100644 (file)
@@ -56,21 +56,16 @@ static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val)
 }
 
 /*H:210
- * The set_guest_interrupt() routine actually delivers the interrupt or
- * trap.  The mechanics of delivering traps and interrupts to the Guest are the
- * same, except some traps have an "error code" which gets pushed onto the
- * stack as well: the caller tells us if this is one.
- *
- * "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this
- * interrupt or trap.  It's split into two parts for traditional reasons: gcc
- * on i386 used to be frightened by 64 bit numbers.
+ * The push_guest_interrupt_stack() routine saves Guest state on the stack for
+ * an interrupt or trap.  The mechanics of delivering traps and interrupts to
+ * the Guest are the same, except some traps have an "error code" which gets
+ * pushed onto the stack as well: the caller tells us if this is one.
  *
  * We set up the stack just like the CPU does for a real interrupt, so it's
  * identical for the Guest (and the standard "iret" instruction will undo
  * it).
  */
-static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
-                               bool has_err)
+static void push_guest_interrupt_stack(struct lg_cpu *cpu, bool has_err)
 {
        unsigned long gstack, origstack;
        u32 eflags, ss, irq_enable;
@@ -130,12 +125,28 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
        if (has_err)
                push_guest_stack(cpu, &gstack, cpu->regs->errcode);
 
-       /*
-        * Now we've pushed all the old state, we change the stack, the code
-        * segment and the address to execute.
-        */
+       /* Adjust the stack pointer and stack segment. */
        cpu->regs->ss = ss;
        cpu->regs->esp = virtstack + (gstack - origstack);
+}
+
+/*
+ * This actually makes the Guest start executing the given interrupt/trap
+ * handler.
+ *
+ * "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this
+ * interrupt or trap.  It's split into two parts for traditional reasons: gcc
+ * on i386 used to be frightened by 64 bit numbers.
+ */
+static void guest_run_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi)
+{
+       /* If we're already in the kernel, we don't change stacks. */
+       if ((cpu->regs->ss&0x3) != GUEST_PL)
+               cpu->regs->ss = cpu->esp1;
+
+       /*
+        * Set the code segment and the address to execute.
+        */
        cpu->regs->cs = (__KERNEL_CS|GUEST_PL);
        cpu->regs->eip = idt_address(lo, hi);
 
@@ -158,6 +169,24 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
                        kill_guest(cpu, "Disabling interrupts");
 }
 
+/* This restores the eflags word which was pushed on the stack by a trap */
+static void restore_eflags(struct lg_cpu *cpu)
+{
+       /* This is the physical address of the stack. */
+       unsigned long stack_pa = guest_pa(cpu, cpu->regs->esp);
+
+       /*
+        * Stack looks like this:
+        * Address      Contents
+        * esp          EIP
+        * esp + 4      CS
+        * esp + 8      EFLAGS
+        */
+       cpu->regs->eflags = lgread(cpu, stack_pa + 8, u32);
+       cpu->regs->eflags &=
+               ~(X86_EFLAGS_TF|X86_EFLAGS_VM|X86_EFLAGS_RF|X86_EFLAGS_NT);
+}
+
 /*H:205
  * Virtual Interrupts.
  *
@@ -200,14 +229,6 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
 
        BUG_ON(irq >= LGUEST_IRQS);
 
-       /*
-        * They may be in the middle of an iret, where they asked us never to
-        * deliver interrupts.
-        */
-       if (cpu->regs->eip >= cpu->lg->noirq_start &&
-          (cpu->regs->eip < cpu->lg->noirq_end))
-               return;
-
        /* If they're halted, interrupts restart them. */
        if (cpu->halted) {
                /* Re-enable interrupts. */
@@ -237,12 +258,34 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
        if (idt_present(idt->a, idt->b)) {
                /* OK, mark it no longer pending and deliver it. */
                clear_bit(irq, cpu->irqs_pending);
+
                /*
-                * set_guest_interrupt() takes the interrupt descriptor and a
-                * flag to say whether this interrupt pushes an error code onto
-                * the stack as well: virtual interrupts never do.
+                * They may be about to iret, where they asked us never to
+                * deliver interrupts.  In this case, we can emulate that iret
+                * then immediately deliver the interrupt.  This is basically
+                * a noop: the iret would pop the interrupt frame and restore
+                * eflags, and then we'd set it up again.  So just restore the
+                * eflags word and jump straight to the handler in this case.
+                *
+                * Denys Vlasenko points out that this isn't quite right: if
+                * the iret was returning to userspace, then that interrupt
+                * would reset the stack pointer (which the Guest told us
+                * about via LHCALL_SET_STACK).  But unless the Guest is being
+                * *really* weird, that will be the same as the current stack
+                * anyway.
                 */
-               set_guest_interrupt(cpu, idt->a, idt->b, false);
+               if (cpu->regs->eip == cpu->lg->noirq_iret) {
+                       restore_eflags(cpu);
+               } else {
+                       /*
+                        * set_guest_interrupt() takes a flag to say whether
+                        * this interrupt pushes an error code onto the stack
+                        * as well: virtual interrupts never do.
+                        */
+                       push_guest_interrupt_stack(cpu, false);
+               }
+               /* Actually make Guest cpu jump to handler. */
+               guest_run_interrupt(cpu, idt->a, idt->b);
        }
 
        /*
@@ -353,8 +396,9 @@ bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
         */
        if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b))
                return false;
-       set_guest_interrupt(cpu, cpu->arch.idt[num].a,
-                           cpu->arch.idt[num].b, has_err(num));
+       push_guest_interrupt_stack(cpu, has_err(num));
+       guest_run_interrupt(cpu, cpu->arch.idt[num].a,
+                           cpu->arch.idt[num].b);
        return true;
 }
 
@@ -395,8 +439,9 @@ static bool direct_trap(unsigned int num)
  * The Guest has the ability to turn its interrupt gates into trap gates,
  * if it is careful.  The Host will let trap gates can go directly to the
  * Guest, but the Guest needs the interrupts atomically disabled for an
- * interrupt gate.  It can do this by pointing the trap gate at instructions
- * within noirq_start and noirq_end, where it can safely disable interrupts.
+ * interrupt gate.  The Host could provide a mechanism to register more
+ * "no-interrupt" regions, and the Guest could point the trap gate at
+ * instructions within that region, where it can safely disable interrupts.
  */
 
 /*M:006
index 307e8b3..ac8ad04 100644 (file)
@@ -102,7 +102,7 @@ struct lguest {
 
        struct pgdir pgdirs[4];
 
-       unsigned long noirq_start, noirq_end;
+       unsigned long noirq_iret;
 
        unsigned int stack_pages;
        u32 tsc_khz;
index c4c6113..30c6068 100644 (file)
@@ -339,6 +339,13 @@ static ssize_t write(struct file *file, const char __user *in,
        }
 }
 
+static int open(struct inode *inode, struct file *file)
+{
+       file->private_data = NULL;
+
+       return 0;
+}
+
 /*L:060
  * The final piece of interface code is the close() routine.  It reverses
  * everything done in initialize().  This is usually called because the
@@ -409,6 +416,7 @@ static int close(struct inode *inode, struct file *file)
  */
 static const struct file_operations lguest_fops = {
        .owner   = THIS_MODULE,
+       .open    = open,
        .release = close,
        .write   = write,
        .read    = read,
index 71d7802..6f1fa17 100644 (file)
@@ -1201,13 +1201,9 @@ static int virtio_ccw_online(struct ccw_device *cdev)
        vcdev->vdev.id.vendor = cdev->id.cu_type;
        vcdev->vdev.id.device = cdev->id.cu_model;
 
-       if (virtio_device_is_legacy_only(vcdev->vdev.id)) {
-               vcdev->revision = 0;
-       } else {
-               ret = virtio_ccw_set_transport_rev(vcdev);
-               if (ret)
-                       goto out_free;
-       }
+       ret = virtio_ccw_set_transport_rev(vcdev);
+       if (ret)
+               goto out_free;
 
        ret = register_virtio_device(&vcdev->vdev);
        if (ret) {
index b546da5..cab9f3f 100644 (file)
@@ -48,6 +48,16 @@ config VIRTIO_BALLOON
 
         If unsure, say M.
 
+config VIRTIO_INPUT
+       tristate "Virtio input driver"
+       depends on VIRTIO
+       depends on INPUT
+       ---help---
+        This driver supports virtio input devices such as
+        keyboards, mice and tablets.
+
+        If unsure, say M.
+
  config VIRTIO_MMIO
        tristate "Platform bus driver for memory mapped virtio devices"
        depends on HAS_IOMEM
index d85565b..41e30e3 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
 virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
 virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
 obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
+obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
index 5ce2aa4..b1877d7 100644 (file)
@@ -278,12 +278,6 @@ static struct bus_type virtio_bus = {
        .remove = virtio_dev_remove,
 };
 
-bool virtio_device_is_legacy_only(struct virtio_device_id id)
-{
-       return id.device == VIRTIO_ID_BALLOON;
-}
-EXPORT_SYMBOL_GPL(virtio_device_is_legacy_only);
-
 int register_virtio_driver(struct virtio_driver *driver)
 {
        /* Catch this early. */
index 6a356e3..82e80e0 100644 (file)
@@ -214,8 +214,8 @@ static inline void update_stat(struct virtio_balloon *vb, int idx,
                               u16 tag, u64 val)
 {
        BUG_ON(idx >= VIRTIO_BALLOON_S_NR);
-       vb->stats[idx].tag = tag;
-       vb->stats[idx].val = val;
+       vb->stats[idx].tag = cpu_to_virtio16(vb->vdev, tag);
+       vb->stats[idx].val = cpu_to_virtio64(vb->vdev, val);
 }
 
 #define pages_to_bytes(x) ((u64)(x) << PAGE_SHIFT)
@@ -283,18 +283,27 @@ static void virtballoon_changed(struct virtio_device *vdev)
 
 static inline s64 towards_target(struct virtio_balloon *vb)
 {
-       __le32 v;
        s64 target;
+       u32 num_pages;
 
-       virtio_cread(vb->vdev, struct virtio_balloon_config, num_pages, &v);
+       virtio_cread(vb->vdev, struct virtio_balloon_config, num_pages,
+                    &num_pages);
 
-       target = le32_to_cpu(v);
+       /* Legacy balloon config space is LE, unlike all other devices. */
+       if (!virtio_has_feature(vb->vdev, VIRTIO_F_VERSION_1))
+               num_pages = le32_to_cpu((__force __le32)num_pages);
+
+       target = num_pages;
        return target - vb->num_pages;
 }
 
 static void update_balloon_size(struct virtio_balloon *vb)
 {
-       __le32 actual = cpu_to_le32(vb->num_pages);
+       u32 actual = vb->num_pages;
+
+       /* Legacy balloon config space is LE, unlike all other devices. */
+       if (!virtio_has_feature(vb->vdev, VIRTIO_F_VERSION_1))
+               actual = (__force u32)cpu_to_le32(actual);
 
        virtio_cwrite(vb->vdev, struct virtio_balloon_config, actual,
                      &actual);
diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
new file mode 100644 (file)
index 0000000..60e2a16
--- /dev/null
@@ -0,0 +1,384 @@
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/input.h>
+
+#include <uapi/linux/virtio_ids.h>
+#include <uapi/linux/virtio_input.h>
+
+struct virtio_input {
+       struct virtio_device       *vdev;
+       struct input_dev           *idev;
+       char                       name[64];
+       char                       serial[64];
+       char                       phys[64];
+       struct virtqueue           *evt, *sts;
+       struct virtio_input_event  evts[64];
+       spinlock_t                 lock;
+       bool                       ready;
+};
+
+static void virtinput_queue_evtbuf(struct virtio_input *vi,
+                                  struct virtio_input_event *evtbuf)
+{
+       struct scatterlist sg[1];
+
+       sg_init_one(sg, evtbuf, sizeof(*evtbuf));
+       virtqueue_add_inbuf(vi->evt, sg, 1, evtbuf, GFP_ATOMIC);
+}
+
+static void virtinput_recv_events(struct virtqueue *vq)
+{
+       struct virtio_input *vi = vq->vdev->priv;
+       struct virtio_input_event *event;
+       unsigned long flags;
+       unsigned int len;
+
+       spin_lock_irqsave(&vi->lock, flags);
+       if (vi->ready) {
+               while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) {
+                       spin_unlock_irqrestore(&vi->lock, flags);
+                       input_event(vi->idev,
+                                   le16_to_cpu(event->type),
+                                   le16_to_cpu(event->code),
+                                   le32_to_cpu(event->value));
+                       spin_lock_irqsave(&vi->lock, flags);
+                       virtinput_queue_evtbuf(vi, event);
+               }
+               virtqueue_kick(vq);
+       }
+       spin_unlock_irqrestore(&vi->lock, flags);
+}
+
+/*
+ * On error we are losing the status update, which isn't critical as
+ * this is typically used for stuff like keyboard leds.
+ */
+static int virtinput_send_status(struct virtio_input *vi,
+                                u16 type, u16 code, s32 value)
+{
+       struct virtio_input_event *stsbuf;
+       struct scatterlist sg[1];
+       unsigned long flags;
+       int rc;
+
+       stsbuf = kzalloc(sizeof(*stsbuf), GFP_ATOMIC);
+       if (!stsbuf)
+               return -ENOMEM;
+
+       stsbuf->type  = cpu_to_le16(type);
+       stsbuf->code  = cpu_to_le16(code);
+       stsbuf->value = cpu_to_le32(value);
+       sg_init_one(sg, stsbuf, sizeof(*stsbuf));
+
+       spin_lock_irqsave(&vi->lock, flags);
+       if (vi->ready) {
+               rc = virtqueue_add_outbuf(vi->sts, sg, 1, stsbuf, GFP_ATOMIC);
+               virtqueue_kick(vi->sts);
+       } else {
+               rc = -ENODEV;
+       }
+       spin_unlock_irqrestore(&vi->lock, flags);
+
+       if (rc != 0)
+               kfree(stsbuf);
+       return rc;
+}
+
+static void virtinput_recv_status(struct virtqueue *vq)
+{
+       struct virtio_input *vi = vq->vdev->priv;
+       struct virtio_input_event *stsbuf;
+       unsigned long flags;
+       unsigned int len;
+
+       spin_lock_irqsave(&vi->lock, flags);
+       while ((stsbuf = virtqueue_get_buf(vi->sts, &len)) != NULL)
+               kfree(stsbuf);
+       spin_unlock_irqrestore(&vi->lock, flags);
+}
+
+static int virtinput_status(struct input_dev *idev, unsigned int type,
+                           unsigned int code, int value)
+{
+       struct virtio_input *vi = input_get_drvdata(idev);
+
+       return virtinput_send_status(vi, type, code, value);
+}
+
+static u8 virtinput_cfg_select(struct virtio_input *vi,
+                              u8 select, u8 subsel)
+{
+       u8 size;
+
+       virtio_cwrite(vi->vdev, struct virtio_input_config, select, &select);
+       virtio_cwrite(vi->vdev, struct virtio_input_config, subsel, &subsel);
+       virtio_cread(vi->vdev, struct virtio_input_config, size, &size);
+       return size;
+}
+
+static void virtinput_cfg_bits(struct virtio_input *vi, int select, int subsel,
+                              unsigned long *bits, unsigned int bitcount)
+{
+       unsigned int bit;
+       u8 *virtio_bits;
+       u8 bytes;
+
+       bytes = virtinput_cfg_select(vi, select, subsel);
+       if (!bytes)
+               return;
+       if (bitcount > bytes * 8)
+               bitcount = bytes * 8;
+
+       /*
+        * Bitmap in virtio config space is a simple stream of bytes,
+        * with the first byte carrying bits 0-7, second bits 8-15 and
+        * so on.
+        */
+       virtio_bits = kzalloc(bytes, GFP_KERNEL);
+       if (!virtio_bits)
+               return;
+       virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,
+                                             u.bitmap),
+                          virtio_bits, bytes);
+       for (bit = 0; bit < bitcount; bit++) {
+               if (virtio_bits[bit / 8] & (1 << (bit % 8)))
+                       __set_bit(bit, bits);
+       }
+       kfree(virtio_bits);
+
+       if (select == VIRTIO_INPUT_CFG_EV_BITS)
+               __set_bit(subsel, vi->idev->evbit);
+}
+
+static void virtinput_cfg_abs(struct virtio_input *vi, int abs)
+{
+       u32 mi, ma, re, fu, fl;
+
+       virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ABS_INFO, abs);
+       virtio_cread(vi->vdev, struct virtio_input_config, u.abs.min, &mi);
+       virtio_cread(vi->vdev, struct virtio_input_config, u.abs.max, &ma);
+       virtio_cread(vi->vdev, struct virtio_input_config, u.abs.res, &re);
+       virtio_cread(vi->vdev, struct virtio_input_config, u.abs.fuzz, &fu);
+       virtio_cread(vi->vdev, struct virtio_input_config, u.abs.flat, &fl);
+       input_set_abs_params(vi->idev, abs, mi, ma, fu, fl);
+       input_abs_set_res(vi->idev, abs, re);
+}
+
+static int virtinput_init_vqs(struct virtio_input *vi)
+{
+       struct virtqueue *vqs[2];
+       vq_callback_t *cbs[] = { virtinput_recv_events,
+                                virtinput_recv_status };
+       static const char *names[] = { "events", "status" };
+       int err;
+
+       err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names);
+       if (err)
+               return err;
+       vi->evt = vqs[0];
+       vi->sts = vqs[1];
+
+       return 0;
+}
+
+static void virtinput_fill_evt(struct virtio_input *vi)
+{
+       unsigned long flags;
+       int i, size;
+
+       spin_lock_irqsave(&vi->lock, flags);
+       size = virtqueue_get_vring_size(vi->evt);
+       if (size > ARRAY_SIZE(vi->evts))
+               size = ARRAY_SIZE(vi->evts);
+       for (i = 0; i < size; i++)
+               virtinput_queue_evtbuf(vi, &vi->evts[i]);
+       virtqueue_kick(vi->evt);
+       spin_unlock_irqrestore(&vi->lock, flags);
+}
+
+static int virtinput_probe(struct virtio_device *vdev)
+{
+       struct virtio_input *vi;
+       unsigned long flags;
+       size_t size;
+       int abs, err;
+
+       if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+               return -ENODEV;
+
+       vi = kzalloc(sizeof(*vi), GFP_KERNEL);
+       if (!vi)
+               return -ENOMEM;
+
+       vdev->priv = vi;
+       vi->vdev = vdev;
+       spin_lock_init(&vi->lock);
+
+       err = virtinput_init_vqs(vi);
+       if (err)
+               goto err_init_vq;
+
+       vi->idev = input_allocate_device();
+       if (!vi->idev) {
+               err = -ENOMEM;
+               goto err_input_alloc;
+       }
+       input_set_drvdata(vi->idev, vi);
+
+       size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_NAME, 0);
+       virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,
+                                             u.string),
+                          vi->name, min(size, sizeof(vi->name)));
+       size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_SERIAL, 0);
+       virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,
+                                             u.string),
+                          vi->serial, min(size, sizeof(vi->serial)));
+       snprintf(vi->phys, sizeof(vi->phys),
+                "virtio%d/input0", vdev->index);
+       vi->idev->name = vi->name;
+       vi->idev->phys = vi->phys;
+       vi->idev->uniq = vi->serial;
+
+       size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_DEVIDS, 0);
+       if (size >= sizeof(struct virtio_input_devids)) {
+               virtio_cread(vi->vdev, struct virtio_input_config,
+                            u.ids.bustype, &vi->idev->id.bustype);
+               virtio_cread(vi->vdev, struct virtio_input_config,
+                            u.ids.vendor, &vi->idev->id.vendor);
+               virtio_cread(vi->vdev, struct virtio_input_config,
+                            u.ids.product, &vi->idev->id.product);
+               virtio_cread(vi->vdev, struct virtio_input_config,
+                            u.ids.version, &vi->idev->id.version);
+       } else {
+               vi->idev->id.bustype = BUS_VIRTUAL;
+       }
+
+       virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_PROP_BITS, 0,
+                          vi->idev->propbit, INPUT_PROP_CNT);
+       size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REP);
+       if (size)
+               __set_bit(EV_REP, vi->idev->evbit);
+
+       vi->idev->dev.parent = &vdev->dev;
+       vi->idev->event = virtinput_status;
+
+       /* device -> kernel */
+       virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY,
+                          vi->idev->keybit, KEY_CNT);
+       virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REL,
+                          vi->idev->relbit, REL_CNT);
+       virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS,
+                          vi->idev->absbit, ABS_CNT);
+       virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_MSC,
+                          vi->idev->mscbit, MSC_CNT);
+       virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SW,
+                          vi->idev->swbit,  SW_CNT);
+
+       /* kernel -> device */
+       virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_LED,
+                          vi->idev->ledbit, LED_CNT);
+       virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SND,
+                          vi->idev->sndbit, SND_CNT);
+
+       if (test_bit(EV_ABS, vi->idev->evbit)) {
+               for (abs = 0; abs < ABS_CNT; abs++) {
+                       if (!test_bit(abs, vi->idev->absbit))
+                               continue;
+                       virtinput_cfg_abs(vi, abs);
+               }
+       }
+
+       virtio_device_ready(vdev);
+       vi->ready = true;
+       err = input_register_device(vi->idev);
+       if (err)
+               goto err_input_register;
+
+       virtinput_fill_evt(vi);
+       return 0;
+
+err_input_register:
+       spin_lock_irqsave(&vi->lock, flags);
+       vi->ready = false;
+       spin_unlock_irqrestore(&vi->lock, flags);
+       input_free_device(vi->idev);
+err_input_alloc:
+       vdev->config->del_vqs(vdev);
+err_init_vq:
+       kfree(vi);
+       return err;
+}
+
+static void virtinput_remove(struct virtio_device *vdev)
+{
+       struct virtio_input *vi = vdev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vi->lock, flags);
+       vi->ready = false;
+       spin_unlock_irqrestore(&vi->lock, flags);
+
+       input_unregister_device(vi->idev);
+       vdev->config->del_vqs(vdev);
+       kfree(vi);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int virtinput_freeze(struct virtio_device *vdev)
+{
+       struct virtio_input *vi = vdev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vi->lock, flags);
+       vi->ready = false;
+       spin_unlock_irqrestore(&vi->lock, flags);
+
+       vdev->config->del_vqs(vdev);
+       return 0;
+}
+
+static int virtinput_restore(struct virtio_device *vdev)
+{
+       struct virtio_input *vi = vdev->priv;
+       int err;
+
+       err = virtinput_init_vqs(vi);
+       if (err)
+               return err;
+
+       virtio_device_ready(vdev);
+       vi->ready = true;
+       virtinput_fill_evt(vi);
+       return 0;
+}
+#endif
+
+static unsigned int features[] = {
+       /* none */
+};
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_INPUT, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static struct virtio_driver virtio_input_driver = {
+       .driver.name         = KBUILD_MODNAME,
+       .driver.owner        = THIS_MODULE,
+       .feature_table       = features,
+       .feature_table_size  = ARRAY_SIZE(features),
+       .id_table            = id_table,
+       .probe               = virtinput_probe,
+       .remove              = virtinput_remove,
+#ifdef CONFIG_PM_SLEEP
+       .freeze              = virtinput_freeze,
+       .restore             = virtinput_restore,
+#endif
+};
+
+module_virtio_driver(virtio_input_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Virtio input device driver");
+MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
index 6010d7e..7a5e60d 100644 (file)
@@ -581,14 +581,6 @@ static int virtio_mmio_probe(struct platform_device *pdev)
        }
        vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID);
 
-       /* Reject legacy-only IDs for version 2 devices */
-       if (vm_dev->version == 2 &&
-                       virtio_device_is_legacy_only(vm_dev->vdev.id)) {
-               dev_err(&pdev->dev, "Version 2 not supported for devices %u!\n",
-                               vm_dev->vdev.id.device);
-               return -ENODEV;
-       }
-
        if (vm_dev->version == 1)
                writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
 
index 2aa38e5..e88e099 100644 (file)
 #define VIRTIO_PCI_NO_LEGACY
 #include "virtio_pci_common.h"
 
+/*
+ * Type-safe wrappers for io accesses.
+ * Use these to enforce at compile time the following spec requirement:
+ *
+ * The driver MUST access each field using the “natural” access
+ * method, i.e. 32-bit accesses for 32-bit fields, 16-bit accesses
+ * for 16-bit fields and 8-bit accesses for 8-bit fields.
+ */
+static inline u8 vp_ioread8(u8 __iomem *addr)
+{
+       return ioread8(addr);
+}
+static inline u16 vp_ioread16 (u16 __iomem *addr)
+{
+       return ioread16(addr);
+}
+
+static inline u32 vp_ioread32(u32 __iomem *addr)
+{
+       return ioread32(addr);
+}
+
+static inline void vp_iowrite8(u8 value, u8 __iomem *addr)
+{
+       iowrite8(value, addr);
+}
+
+static inline void vp_iowrite16(u16 value, u16 __iomem *addr)
+{
+       iowrite16(value, addr);
+}
+
+static inline void vp_iowrite32(u32 value, u32 __iomem *addr)
+{
+       iowrite32(value, addr);
+}
+
+static void vp_iowrite64_twopart(u64 val,
+                                __le32 __iomem *lo, __le32 __iomem *hi)
+{
+       vp_iowrite32((u32)val, lo);
+       vp_iowrite32(val >> 32, hi);
+}
+
 static void __iomem *map_capability(struct pci_dev *dev, int off,
                                    size_t minlen,
                                    u32 align,
@@ -94,22 +138,16 @@ static void __iomem *map_capability(struct pci_dev *dev, int off,
        return p;
 }
 
-static void iowrite64_twopart(u64 val, __le32 __iomem *lo, __le32 __iomem *hi)
-{
-       iowrite32((u32)val, lo);
-       iowrite32(val >> 32, hi);
-}
-
 /* virtio config->get_features() implementation */
 static u64 vp_get_features(struct virtio_device *vdev)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        u64 features;
 
-       iowrite32(0, &vp_dev->common->device_feature_select);
-       features = ioread32(&vp_dev->common->device_feature);
-       iowrite32(1, &vp_dev->common->device_feature_select);
-       features |= ((u64)ioread32(&vp_dev->common->device_feature) << 32);
+       vp_iowrite32(0, &vp_dev->common->device_feature_select);
+       features = vp_ioread32(&vp_dev->common->device_feature);
+       vp_iowrite32(1, &vp_dev->common->device_feature_select);
+       features |= ((u64)vp_ioread32(&vp_dev->common->device_feature) << 32);
 
        return features;
 }
@@ -128,10 +166,10 @@ static int vp_finalize_features(struct virtio_device *vdev)
                return -EINVAL;
        }
 
-       iowrite32(0, &vp_dev->common->guest_feature_select);
-       iowrite32((u32)vdev->features, &vp_dev->common->guest_feature);
-       iowrite32(1, &vp_dev->common->guest_feature_select);
-       iowrite32(vdev->features >> 32, &vp_dev->common->guest_feature);
+       vp_iowrite32(0, &vp_dev->common->guest_feature_select);
+       vp_iowrite32((u32)vdev->features, &vp_dev->common->guest_feature);
+       vp_iowrite32(1, &vp_dev->common->guest_feature_select);
+       vp_iowrite32(vdev->features >> 32, &vp_dev->common->guest_feature);
 
        return 0;
 }
@@ -210,14 +248,14 @@ static void vp_set(struct virtio_device *vdev, unsigned offset,
 static u32 vp_generation(struct virtio_device *vdev)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       return ioread8(&vp_dev->common->config_generation);
+       return vp_ioread8(&vp_dev->common->config_generation);
 }
 
 /* config->{get,set}_status() implementations */
 static u8 vp_get_status(struct virtio_device *vdev)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       return ioread8(&vp_dev->common->device_status);
+       return vp_ioread8(&vp_dev->common->device_status);
 }
 
 static void vp_set_status(struct virtio_device *vdev, u8 status)
@@ -225,17 +263,17 @@ static void vp_set_status(struct virtio_device *vdev, u8 status)
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        /* We should never be setting status to 0. */
        BUG_ON(status == 0);
-       iowrite8(status, &vp_dev->common->device_status);
+       vp_iowrite8(status, &vp_dev->common->device_status);
 }
 
 static void vp_reset(struct virtio_device *vdev)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        /* 0 status means a reset. */
-       iowrite8(0, &vp_dev->common->device_status);
+       vp_iowrite8(0, &vp_dev->common->device_status);
        /* Flush out the status write, and flush in device writes,
         * including MSI-X interrupts, if any. */
-       ioread8(&vp_dev->common->device_status);
+       vp_ioread8(&vp_dev->common->device_status);
        /* Flush pending VQ/configuration callbacks. */
        vp_synchronize_vectors(vdev);
 }
@@ -243,10 +281,10 @@ static void vp_reset(struct virtio_device *vdev)
 static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector)
 {
        /* Setup the vector used for configuration events */
-       iowrite16(vector, &vp_dev->common->msix_config);
+       vp_iowrite16(vector, &vp_dev->common->msix_config);
        /* Verify we had enough resources to assign the vector */
        /* Will also flush the write out to device */
-       return ioread16(&vp_dev->common->msix_config);
+       return vp_ioread16(&vp_dev->common->msix_config);
 }
 
 static size_t vring_pci_size(u16 num)
@@ -286,15 +324,15 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
        u16 num, off;
        int err;
 
-       if (index >= ioread16(&cfg->num_queues))
+       if (index >= vp_ioread16(&cfg->num_queues))
                return ERR_PTR(-ENOENT);
 
        /* Select the queue we're interested in */
-       iowrite16(index, &cfg->queue_select);
+       vp_iowrite16(index, &cfg->queue_select);
 
        /* Check if queue is either not available or already active. */
-       num = ioread16(&cfg->queue_size);
-       if (!num || ioread16(&cfg->queue_enable))
+       num = vp_ioread16(&cfg->queue_size);
+       if (!num || vp_ioread16(&cfg->queue_enable))
                return ERR_PTR(-ENOENT);
 
        if (num & (num - 1)) {
@@ -303,7 +341,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
        }
 
        /* get offset of notification word for this vq */
-       off = ioread16(&cfg->queue_notify_off);
+       off = vp_ioread16(&cfg->queue_notify_off);
 
        info->num = num;
        info->msix_vector = msix_vec;
@@ -322,13 +360,13 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
        }
 
        /* activate the queue */
-       iowrite16(num, &cfg->queue_size);
-       iowrite64_twopart(virt_to_phys(info->queue),
-                         &cfg->queue_desc_lo, &cfg->queue_desc_hi);
-       iowrite64_twopart(virt_to_phys(virtqueue_get_avail(vq)),
-                         &cfg->queue_avail_lo, &cfg->queue_avail_hi);
-       iowrite64_twopart(virt_to_phys(virtqueue_get_used(vq)),
-                         &cfg->queue_used_lo, &cfg->queue_used_hi);
+       vp_iowrite16(num, &cfg->queue_size);
+       vp_iowrite64_twopart(virt_to_phys(info->queue),
+                            &cfg->queue_desc_lo, &cfg->queue_desc_hi);
+       vp_iowrite64_twopart(virt_to_phys(virtqueue_get_avail(vq)),
+                            &cfg->queue_avail_lo, &cfg->queue_avail_hi);
+       vp_iowrite64_twopart(virt_to_phys(virtqueue_get_used(vq)),
+                            &cfg->queue_used_lo, &cfg->queue_used_hi);
 
        if (vp_dev->notify_base) {
                /* offset should not wrap */
@@ -357,8 +395,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
        }
 
        if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
-               iowrite16(msix_vec, &cfg->queue_msix_vector);
-               msix_vec = ioread16(&cfg->queue_msix_vector);
+               vp_iowrite16(msix_vec, &cfg->queue_msix_vector);
+               msix_vec = vp_ioread16(&cfg->queue_msix_vector);
                if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
                        err = -EBUSY;
                        goto err_assign_vector;
@@ -393,8 +431,8 @@ static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs,
         * this, there's no way to go back except reset.
         */
        list_for_each_entry(vq, &vdev->vqs, list) {
-               iowrite16(vq->index, &vp_dev->common->queue_select);
-               iowrite16(1, &vp_dev->common->queue_enable);
+               vp_iowrite16(vq->index, &vp_dev->common->queue_select);
+               vp_iowrite16(1, &vp_dev->common->queue_enable);
        }
 
        return 0;
@@ -405,13 +443,13 @@ static void del_vq(struct virtio_pci_vq_info *info)
        struct virtqueue *vq = info->vq;
        struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
 
-       iowrite16(vq->index, &vp_dev->common->queue_select);
+       vp_iowrite16(vq->index, &vp_dev->common->queue_select);
 
        if (vp_dev->msix_enabled) {
-               iowrite16(VIRTIO_MSI_NO_VECTOR,
-                         &vp_dev->common->queue_msix_vector);
+               vp_iowrite16(VIRTIO_MSI_NO_VECTOR,
+                            &vp_dev->common->queue_msix_vector);
                /* Flush the write out to device */
-               ioread16(&vp_dev->common->queue_msix_vector);
+               vp_ioread16(&vp_dev->common->queue_msix_vector);
        }
 
        if (!vp_dev->notify_base)
@@ -577,9 +615,6 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
        }
        vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
 
-       if (virtio_device_is_legacy_only(vp_dev->vdev.id))
-               return -ENODEV;
-
        /* check for a common config: if not, use legacy mode (bar 0). */
        common = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_COMMON_CFG,
                                            IORESOURCE_IO | IORESOURCE_MEM);
index 9962c6b..6db19f3 100644 (file)
@@ -61,8 +61,8 @@ struct lguest_data {
        u32 tsc_khz;
 
 /* Fields initialized by the Guest at boot: */
-       /* Instruction range to suppress interrupts even if enabled */
-       unsigned long noirq_start, noirq_end;
+       /* Instruction to suppress interrupts even if enabled */
+       unsigned long noirq_iret;
        /* Address above which page tables are all identical. */
        unsigned long kernel_address;
        /* The vector to try to use for system calls (0x40 or 0x80). */
index 28f0e65..8f4d4bf 100644 (file)
@@ -108,8 +108,6 @@ struct virtio_device {
        void *priv;
 };
 
-bool virtio_device_is_legacy_only(struct virtio_device_id id);
-
 static inline struct virtio_device *dev_to_virtio(struct device *_dev)
 {
        return container_of(_dev, struct virtio_device, dev);
index ca3ed78..1e306f7 100644 (file)
@@ -298,13 +298,6 @@ static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
                }                                                       \
        } while(0)
 
-static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset)
-{
-       u8 ret;
-       vdev->config->get(vdev, offset, &ret, sizeof(ret));
-       return ret;
-}
-
 /* Read @count fields, @bytes each. */
 static inline void __virtio_cread_many(struct virtio_device *vdev,
                                       unsigned int offset,
@@ -326,7 +319,6 @@ static inline void __virtio_cread_many(struct virtio_device *vdev,
        } while (gen != old);
 }
 
-
 static inline void virtio_cread_bytes(struct virtio_device *vdev,
                                      unsigned int offset,
                                      void *buf, size_t len)
@@ -334,6 +326,13 @@ static inline void virtio_cread_bytes(struct virtio_device *vdev,
        __virtio_cread_many(vdev, offset, buf, len, 1);
 }
 
+static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset)
+{
+       u8 ret;
+       vdev->config->get(vdev, offset, &ret, sizeof(ret));
+       return ret;
+}
+
 static inline void virtio_cwrite8(struct virtio_device *vdev,
                                  unsigned int offset, u8 val)
 {
@@ -374,7 +373,6 @@ static inline u64 virtio_cread64(struct virtio_device *vdev,
                                 unsigned int offset)
 {
        u64 ret;
-       vdev->config->get(vdev, offset, &ret, sizeof(ret));
        __virtio_cread_many(vdev, offset, &ret, 1, sizeof(ret));
        return virtio64_to_cpu(vdev, (__force __virtio64)ret);
 }
index 67e06fe..8e50888 100644 (file)
  * actually quite cheap.
  */
 
-#ifdef CONFIG_SMP
 static inline void virtio_mb(bool weak_barriers)
 {
+#ifdef CONFIG_SMP
        if (weak_barriers)
                smp_mb();
        else
+#endif
                mb();
 }
 
 static inline void virtio_rmb(bool weak_barriers)
 {
        if (weak_barriers)
-               smp_rmb();
+               dma_rmb();
        else
                rmb();
 }
@@ -41,26 +42,10 @@ static inline void virtio_rmb(bool weak_barriers)
 static inline void virtio_wmb(bool weak_barriers)
 {
        if (weak_barriers)
-               smp_wmb();
+               dma_wmb();
        else
                wmb();
 }
-#else
-static inline void virtio_mb(bool weak_barriers)
-{
-       mb();
-}
-
-static inline void virtio_rmb(bool weak_barriers)
-{
-       rmb();
-}
-
-static inline void virtio_wmb(bool weak_barriers)
-{
-       wmb();
-}
-#endif
 
 struct virtio_device;
 struct virtqueue;
index 640954b..1a0006a 100644 (file)
@@ -431,6 +431,7 @@ header-y += virtio_blk.h
 header-y += virtio_config.h
 header-y += virtio_console.h
 header-y += virtio_ids.h
+header-y += virtio_input.h
 header-y += virtio_net.h
 header-y += virtio_pci.h
 header-y += virtio_ring.h
index 4b0488f..984169a 100644 (file)
@@ -25,6 +25,7 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE. */
+#include <linux/types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
 
@@ -38,9 +39,9 @@
 
 struct virtio_balloon_config {
        /* Number of pages host wants Guest to give up. */
-       __le32 num_pages;
+       __u32 num_pages;
        /* Number of pages we've actually got in balloon. */
-       __le32 actual;
+       __u32 actual;
 };
 
 #define VIRTIO_BALLOON_S_SWAP_IN  0   /* Amount of memory swapped in */
@@ -51,9 +52,32 @@ struct virtio_balloon_config {
 #define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
 #define VIRTIO_BALLOON_S_NR       6
 
+/*
+ * Memory statistics structure.
+ * Driver fills an array of these structures and passes to device.
+ *
+ * NOTE: fields are laid out in a way that would make compiler add padding
+ * between and after fields, so we have to use compiler-specific attributes to
+ * pack it, to disable this padding. This also often causes compiler to
+ * generate suboptimal code.
+ *
+ * We maintain this statistics structure format for backwards compatibility,
+ * but don't follow this example.
+ *
+ * If implementing a similar structure, do something like the below instead:
+ *     struct virtio_balloon_stat {
+ *         __virtio16 tag;
+ *         __u8 reserved[6];
+ *         __virtio64 val;
+ *     };
+ *
+ * In other words, add explicit reserved fields to align field and
+ * structure boundaries at field size, avoiding compiler padding
+ * without the packed attribute.
+ */
 struct virtio_balloon_stat {
-       __u16 tag;
-       __u64 val;
+       __virtio16 tag;
+       __virtio64 val;
 } __attribute__((packed));
 
 #endif /* _LINUX_VIRTIO_BALLOON_H */
index 284fc3a..5f60aa4 100644 (file)
@@ -39,5 +39,6 @@
 #define VIRTIO_ID_9P           9 /* 9p virtio console */
 #define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */
 #define VIRTIO_ID_CAIF        12 /* Virtio caif */
+#define VIRTIO_ID_INPUT        18 /* virtio input */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/uapi/linux/virtio_input.h b/include/uapi/linux/virtio_input.h
new file mode 100644 (file)
index 0000000..a7fe5c8
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef _LINUX_VIRTIO_INPUT_H
+#define _LINUX_VIRTIO_INPUT_H
+/* This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+#include <linux/types.h>
+
+enum virtio_input_config_select {
+       VIRTIO_INPUT_CFG_UNSET      = 0x00,
+       VIRTIO_INPUT_CFG_ID_NAME    = 0x01,
+       VIRTIO_INPUT_CFG_ID_SERIAL  = 0x02,
+       VIRTIO_INPUT_CFG_ID_DEVIDS  = 0x03,
+       VIRTIO_INPUT_CFG_PROP_BITS  = 0x10,
+       VIRTIO_INPUT_CFG_EV_BITS    = 0x11,
+       VIRTIO_INPUT_CFG_ABS_INFO   = 0x12,
+};
+
+struct virtio_input_absinfo {
+       __u32 min;
+       __u32 max;
+       __u32 fuzz;
+       __u32 flat;
+       __u32 res;
+};
+
+struct virtio_input_devids {
+       __u16 bustype;
+       __u16 vendor;
+       __u16 product;
+       __u16 version;
+};
+
+struct virtio_input_config {
+       __u8    select;
+       __u8    subsel;
+       __u8    size;
+       __u8    reserved[5];
+       union {
+               char string[128];
+               __u8 bitmap[128];
+               struct virtio_input_absinfo abs;
+               struct virtio_input_devids ids;
+       } u;
+};
+
+struct virtio_input_event {
+       __le16 type;
+       __le16 code;
+       __le32 value;
+};
+
+#endif /* _LINUX_VIRTIO_INPUT_H */