Input: xen-kbdfront - add grant reference for shared page
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>
Thu, 17 Mar 2011 05:52:42 +0000 (22:52 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 17 Mar 2011 06:24:07 +0000 (23:24 -0700)
Without a grant reference, full access to the domain's memory is
required to use the shared page. Add an additional parameter in
xenstore to allow grant mapping to be used.

Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Acked-by: Ian Campbell <Ian.Campbell@eu.citrix.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/input/xen-kbdfront.c

index 53e62732ee96f5976e1515f67f6beb0ff6deb461..7077f9bf5ead88a15eb65699e71d00e49715fc84 100644 (file)
  *  more details.
  */
 
-/*
- * TODO:
- *
- * Switch to grant tables together with xen-fbfront.c.
- */
-
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
@@ -30,6 +24,8 @@
 #include <xen/xen.h>
 #include <xen/events.h>
 #include <xen/page.h>
+#include <xen/grant_table.h>
+#include <xen/interface/grant_table.h>
 #include <xen/interface/io/fbif.h>
 #include <xen/interface/io/kbdif.h>
 #include <xen/xenbus.h>
@@ -38,6 +34,7 @@ struct xenkbd_info {
        struct input_dev *kbd;
        struct input_dev *ptr;
        struct xenkbd_page *page;
+       int gref;
        int irq;
        struct xenbus_device *xbdev;
        char phys[32];
@@ -122,6 +119,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev,
        dev_set_drvdata(&dev->dev, info);
        info->xbdev = dev;
        info->irq = -1;
+       info->gref = -1;
        snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
 
        info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
@@ -232,15 +230,20 @@ static int xenkbd_connect_backend(struct xenbus_device *dev,
        int ret, evtchn;
        struct xenbus_transaction xbt;
 
+       ret = gnttab_grant_foreign_access(dev->otherend_id,
+                                         virt_to_mfn(info->page), 0);
+       if (ret < 0)
+               return ret;
+       info->gref = ret;
+
        ret = xenbus_alloc_evtchn(dev, &evtchn);
        if (ret)
-               return ret;
+               goto error_grant;
        ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
                                        0, dev->devicetype, info);
        if (ret < 0) {
-               xenbus_free_evtchn(dev, evtchn);
                xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
-               return ret;
+               goto error_evtchan;
        }
        info->irq = ret;
 
@@ -248,10 +251,13 @@ static int xenkbd_connect_backend(struct xenbus_device *dev,
        ret = xenbus_transaction_start(&xbt);
        if (ret) {
                xenbus_dev_fatal(dev, ret, "starting transaction");
-               return ret;
+               goto error_irqh;
        }
        ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
                            virt_to_mfn(info->page));
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref);
        if (ret)
                goto error_xenbus;
        ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
@@ -263,7 +269,7 @@ static int xenkbd_connect_backend(struct xenbus_device *dev,
                if (ret == -EAGAIN)
                        goto again;
                xenbus_dev_fatal(dev, ret, "completing transaction");
-               return ret;
+               goto error_irqh;
        }
 
        xenbus_switch_state(dev, XenbusStateInitialised);
@@ -272,6 +278,14 @@ static int xenkbd_connect_backend(struct xenbus_device *dev,
  error_xenbus:
        xenbus_transaction_end(xbt, 1);
        xenbus_dev_fatal(dev, ret, "writing xenstore");
+ error_irqh:
+       unbind_from_irqhandler(info->irq, info);
+       info->irq = -1;
+ error_evtchan:
+       xenbus_free_evtchn(dev, evtchn);
+ error_grant:
+       gnttab_end_foreign_access_ref(info->gref, 0);
+       info->gref = -1;
        return ret;
 }
 
@@ -280,6 +294,9 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info)
        if (info->irq >= 0)
                unbind_from_irqhandler(info->irq, info);
        info->irq = -1;
+       if (info->gref >= 0)
+               gnttab_end_foreign_access_ref(info->gref, 0);
+       info->gref = -1;
 }
 
 static void xenkbd_backend_changed(struct xenbus_device *dev,