Merge remote-tracking branch 'sstabellini/tags/xen-20161122-tag' into staging

Xen 2016/11/22

# gpg: Signature made Tue 22 Nov 2016 06:41:23 PM GMT
# gpg:                using RSA key 0x894F8F4870E1AE90
# gpg: Good signature from "Stefano Stabellini <sstabellini@kernel.org>"
# gpg:                 aka "Stefano Stabellini <stefano.stabellini@eu.citrix.com>"
# Primary key fingerprint: D04E 33AB A51F 67BA 07D3  0AEA 894F 8F48 70E1 AE90

* sstabellini/tags/xen-20161122-tag:
  xen: attach pvusb usb bus to backend qdev
  xen: create qdev for each backend device
  qdev: add function qdev_set_id()
  xen: add an own bus for xen backend devices
  xen: fix ioreq handling

Message-id: alpine.DEB.2.10.1611221037010.21858@sstabellini-ThinkPad-X260
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c
index 1b3c2fb..8e676e6 100644
--- a/hw/usb/xen-usb.c
+++ b/hw/usb/xen-usb.c
@@ -712,15 +712,10 @@
 
 static void usbback_portid_remove(struct usbback_info *usbif, unsigned port)
 {
-    USBPort *p;
-
     if (!usbif->ports[port - 1].dev) {
         return;
     }
 
-    p = &(usbif->ports[port - 1].port);
-    snprintf(p->path, sizeof(p->path), "%d", 99);
-
     object_unparent(OBJECT(usbif->ports[port - 1].dev));
     usbif->ports[port - 1].dev = NULL;
     usbback_portid_detach(usbif, port);
@@ -733,10 +728,10 @@
 {
     unsigned speed;
     char *portname;
-    USBPort *p;
     Error *local_err = NULL;
     QDict *qdict;
     QemuOpts *opts;
+    char *tmp;
 
     if (usbif->ports[port - 1].dev) {
         return;
@@ -749,11 +744,16 @@
         return;
     }
     portname++;
-    p = &(usbif->ports[port - 1].port);
-    snprintf(p->path, sizeof(p->path), "%s", portname);
 
     qdict = qdict_new();
     qdict_put(qdict, "driver", qstring_from_str("usb-host"));
+    tmp = g_strdup_printf("%s.0", usbif->xendev.qdev.id);
+    qdict_put(qdict, "bus", qstring_from_str(tmp));
+    g_free(tmp);
+    tmp = g_strdup_printf("%s-%u", usbif->xendev.qdev.id, port);
+    qdict_put(qdict, "id", qstring_from_str(tmp));
+    g_free(tmp);
+    qdict_put(qdict, "port", qint_from_int(port));
     qdict_put(qdict, "hostbus", qint_from_int(atoi(busid)));
     qdict_put(qdict, "hostport", qstring_from_str(portname));
     opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
@@ -765,7 +765,6 @@
         goto err;
     }
     QDECREF(qdict);
-    snprintf(p->path, sizeof(p->path), "%d", port);
     speed = usbif->ports[port - 1].dev->speed;
     switch (speed) {
     case USB_SPEED_LOW:
@@ -799,7 +798,6 @@
 
 err:
     QDECREF(qdict);
-    snprintf(p->path, sizeof(p->path), "%d", 99);
     xen_pv_printf(&usbif->xendev, 0, "device %s could not be opened\n", busid);
 }
 
@@ -1012,13 +1010,13 @@
 
     usbif = container_of(xendev, struct usbback_info, xendev);
 
-    usb_bus_new(&usbif->bus, sizeof(usbif->bus), &xen_usb_bus_ops, xen_sysdev);
+    usb_bus_new(&usbif->bus, sizeof(usbif->bus), &xen_usb_bus_ops,
+                DEVICE(&xendev->qdev));
     for (i = 0; i < USBBACK_MAXPORTS; i++) {
         p = &(usbif->ports[i].port);
         usb_register_port(&usbif->bus, p, usbif, i, &xen_usb_port_ops,
                           USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
                           USB_SPEED_MASK_HIGH);
-        snprintf(p->path, sizeof(p->path), "%d", 99);
     }
 
     QTAILQ_INIT(&usbif->req_free_q);
@@ -1066,7 +1064,6 @@
     }
 
     usb_bus_release(&usbif->bus);
-    object_unparent(OBJECT(&usbif->bus));
 
     TR_BUS(xendev, "finished\n");
 
diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
index 41ba5c5..d119004 100644
--- a/hw/xen/xen_backend.c
+++ b/hw/xen/xen_backend.c
@@ -27,16 +27,18 @@
 
 #include "hw/hw.h"
 #include "hw/sysbus.h"
+#include "hw/boards.h"
 #include "sysemu/char.h"
 #include "qemu/log.h"
+#include "qapi/error.h"
 #include "hw/xen/xen_backend.h"
 #include "hw/xen/xen_pvdev.h"
+#include "monitor/qdev.h"
 
 #include <xen/grant_table.h>
 
-#define TYPE_XENSYSDEV "xensysdev"
-
 DeviceState *xen_sysdev;
+BusState *xen_sysbus;
 
 /* ------------------------------------------------------------- */
 
@@ -121,6 +123,12 @@
 
     /* init new xendev */
     xendev = g_malloc0(ops->size);
+    object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND);
+    qdev_set_parent_bus(&xendev->qdev, xen_sysbus);
+    qdev_set_id(&xendev->qdev, g_strdup_printf("xen-%s-%d", type, dev));
+    qdev_init_nofail(&xendev->qdev);
+    object_unref(OBJECT(&xendev->qdev));
+
     xendev->type  = type;
     xendev->dom   = dom;
     xendev->dev   = dev;
@@ -528,6 +536,8 @@
 
     xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV);
     qdev_init_nofail(xen_sysdev);
+    xen_sysbus = qbus_create(TYPE_XENSYSBUS, DEVICE(xen_sysdev), "xen-sysbus");
+    qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort);
 
     return 0;
 
@@ -539,6 +549,15 @@
     return -1;
 }
 
+static void xen_set_dynamic_sysbus(void)
+{
+    Object *machine = qdev_get_machine();
+    ObjectClass *oc = object_get_class(machine);
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->has_dynamic_sysbus = true;
+}
+
 int xen_be_register(const char *type, struct XenDevOps *ops)
 {
     char path[50];
@@ -560,6 +579,8 @@
 
 void xen_be_register_common(void)
 {
+    xen_set_dynamic_sysbus();
+
     xen_be_register("console", &xen_console_ops);
     xen_be_register("vkbd", &xen_kbdmouse_ops);
     xen_be_register("qdisk", &xen_blkdev_ops);
@@ -586,6 +607,42 @@
 }
 
 
+static Property xendev_properties[] = {
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xendev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = xendev_properties;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo xendev_type_info = {
+    .name          = TYPE_XENBACKEND,
+    .parent        = TYPE_XENSYSDEV,
+    .class_init    = xendev_class_init,
+    .instance_size = sizeof(struct XenDevice),
+};
+
+static void xen_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
+
+    hc->unplug = qdev_simple_device_unplug_cb;
+}
+
+static const TypeInfo xensysbus_info = {
+    .name       = TYPE_XENSYSBUS,
+    .parent     = TYPE_BUS,
+    .class_init = xen_sysbus_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_HOTPLUG_HANDLER },
+        { }
+    }
+};
+
 static int xen_sysdev_init(SysBusDevice *dev)
 {
     return 0;
@@ -602,6 +659,7 @@
 
     k->init = xen_sysdev_init;
     dc->props = xen_sysdev_properties;
+    dc->bus_type = TYPE_XENSYSBUS;
 }
 
 static const TypeInfo xensysdev_info = {
@@ -613,7 +671,9 @@
 
 static void xenbe_register_types(void)
 {
+    type_register_static(&xensysbus_info);
     type_register_static(&xensysdev_info);
+    type_register_static(&xendev_type_info);
 }
 
-type_init(xenbe_register_types);
+type_init(xenbe_register_types)
diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
index 5212bc6..aed783e 100644
--- a/hw/xen/xen_pvdev.c
+++ b/hw/xen/xen_pvdev.c
@@ -19,6 +19,7 @@
 
 #include "qemu/osdep.h"
 #include "qemu/log.h"
+#include "hw/qdev-core.h"
 #include "hw/xen/xen_backend.h"
 #include "hw/xen/xen_pvdev.h"
 
@@ -307,7 +308,8 @@
     }
 
     QTAILQ_REMOVE(&xendevs, xendev, next);
-    g_free(xendev);
+
+    qdev_unplug(&xendev->qdev, NULL);
 }
 
 void xen_pv_insert_xendev(struct XenDevice *xendev)
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
index cbda40e..4f4799a 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen_backend.h
@@ -6,12 +6,20 @@
 #include "sysemu/sysemu.h"
 #include "net/net.h"
 
+#define TYPE_XENSYSDEV "xen-sysdev"
+#define TYPE_XENSYSBUS "xen-sysbus"
+#define TYPE_XENBACKEND "xen-backend"
+
+#define XENBACKEND_DEVICE(obj) \
+    OBJECT_CHECK(XenDevice, (obj), TYPE_XENBACKEND)
+
 /* variables */
 extern xc_interface *xen_xc;
 extern xenforeignmemory_handle *xen_fmem;
 extern struct xs_handle *xenstore;
 extern const char *xen_protocol;
 extern DeviceState *xen_sysdev;
+extern BusState *xen_sysbus;
 
 int xenstore_mkdir(char *path, int p);
 int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
diff --git a/include/hw/xen/xen_pvdev.h b/include/hw/xen/xen_pvdev.h
index 083f0a9..d473e9b 100644
--- a/include/hw/xen/xen_pvdev.h
+++ b/include/hw/xen/xen_pvdev.h
@@ -29,6 +29,7 @@
 };
 
 struct XenDevice {
+    DeviceState        qdev;
     const char         *type;
     int                dom;
     int                dev;
diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h
index 8e504bc..0ff3331 100644
--- a/include/monitor/qdev.h
+++ b/include/monitor/qdev.h
@@ -12,5 +12,6 @@
 
 int qdev_device_help(QemuOpts *opts);
 DeviceState *qdev_device_add(QemuOpts *opts, Error **errp);
+void qdev_set_id(DeviceState *dev, const char *id);
 
 #endif
diff --git a/qdev-monitor.c b/qdev-monitor.c
index 4f78ecb..c73410c 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -539,10 +539,28 @@
     return bus;
 }
 
+void qdev_set_id(DeviceState *dev, const char *id)
+{
+    if (id) {
+        dev->id = id;
+    }
+
+    if (dev->id) {
+        object_property_add_child(qdev_get_peripheral(), dev->id,
+                                  OBJECT(dev), NULL);
+    } else {
+        static int anon_count;
+        gchar *name = g_strdup_printf("device[%d]", anon_count++);
+        object_property_add_child(qdev_get_peripheral_anon(), name,
+                                  OBJECT(dev), NULL);
+        g_free(name);
+    }
+}
+
 DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
 {
     DeviceClass *dc;
-    const char *driver, *path, *id;
+    const char *driver, *path;
     DeviceState *dev;
     BusState *bus = NULL;
     Error *err = NULL;
@@ -591,21 +609,7 @@
         qdev_set_parent_bus(dev, bus);
     }
 
-    id = qemu_opts_id(opts);
-    if (id) {
-        dev->id = id;
-    }
-
-    if (dev->id) {
-        object_property_add_child(qdev_get_peripheral(), dev->id,
-                                  OBJECT(dev), NULL);
-    } else {
-        static int anon_count;
-        gchar *name = g_strdup_printf("device[%d]", anon_count++);
-        object_property_add_child(qdev_get_peripheral_anon(), name,
-                                  OBJECT(dev), NULL);
-        g_free(name);
-    }
+    qdev_set_id(dev, qemu_opts_id(opts));
 
     /* set properties */
     if (qemu_opt_foreach(opts, set_property, dev, &err)) {
diff --git a/xen-hvm.c b/xen-hvm.c
index 150c7e7..99b8ee8 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -810,6 +810,10 @@
     trace_cpu_ioreq_pio(req, req->dir, req->df, req->data_is_ptr, req->addr,
                          req->data, req->count, req->size);
 
+    if (req->size > sizeof(uint32_t)) {
+        hw_error("PIO: bad size (%u)", req->size);
+    }
+
     if (req->dir == IOREQ_READ) {
         if (!req->data_is_ptr) {
             req->data = do_inp(req->addr, req->size);
@@ -846,6 +850,10 @@
     trace_cpu_ioreq_move(req, req->dir, req->df, req->data_is_ptr, req->addr,
                          req->data, req->count, req->size);
 
+    if (req->size > sizeof(req->data)) {
+        hw_error("MMIO: bad size (%u)", req->size);
+    }
+
     if (!req->data_is_ptr) {
         if (req->dir == IOREQ_READ) {
             for (i = 0; i < req->count; i++) {
@@ -1010,11 +1018,13 @@
         req.df = 1;
         req.type = buf_req->type;
         req.data_is_ptr = 0;
+        xen_rmb();
         qw = (req.size == 8);
         if (qw) {
             buf_req = &buf_page->buf_ioreq[(rdptr + 1) %
                                            IOREQ_BUFFER_SLOT_NUM];
             req.data |= ((uint64_t)buf_req->data) << 32;
+            xen_rmb();
         }
 
         handle_ioreq(state, &req);
@@ -1045,7 +1055,11 @@
 
     handle_buffered_iopage(state);
     if (req) {
-        handle_ioreq(state, req);
+        ioreq_t copy = *req;
+
+        xen_rmb();
+        handle_ioreq(state, &copy);
+        req->data = copy.data;
 
         if (req->state != STATE_IOREQ_INPROCESS) {
             fprintf(stderr, "Badness in I/O request ... not in service?!: "