* [Qemu-devel] [PATCH 1/4] usb-host: live migration support for the libusb version
2013-05-07 9:50 [Qemu-devel] [PULL for-1.5 0/4] usb patch qeue Gerd Hoffmann
@ 2013-05-07 9:50 ` Gerd Hoffmann
2013-05-07 9:50 ` [Qemu-devel] [PATCH 2/4] usb-host: add usb_host_full_speed_compat Gerd Hoffmann
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2013-05-07 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/host-libusb.c | 54 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 49 insertions(+), 5 deletions(-)
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index d1186b8..ee67c4c 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -94,7 +94,8 @@ struct USBHostDevice {
} ifs[USB_MAX_INTERFACES];
/* callbacks & friends */
- QEMUBH *bh;
+ QEMUBH *bh_nodev;
+ QEMUBH *bh_postld;
Notifier exit;
/* request queues */
@@ -835,10 +836,10 @@ static void usb_host_nodev_bh(void *opaque)
static void usb_host_nodev(USBHostDevice *s)
{
- if (!s->bh) {
- s->bh = qemu_bh_new(usb_host_nodev_bh, s);
+ if (!s->bh_nodev) {
+ s->bh_nodev = qemu_bh_new(usb_host_nodev_bh, s);
}
- qemu_bh_schedule(s->bh);
+ qemu_bh_schedule(s->bh_nodev);
}
static void usb_host_exit_notifier(struct Notifier *n, void *data)
@@ -1228,9 +1229,52 @@ static void usb_host_handle_reset(USBDevice *udev)
usb_host_ep_update(s);
}
+/*
+ * This is *NOT* about restoring state. We have absolutely no idea
+ * what state the host device is in at the moment and whenever it is
+ * still present in the first place. Attemping to contine where we
+ * left off is impossible.
+ *
+ * What we are going to to to here is emulate a surprise removal of
+ * the usb device passed through, then kick host scan so the device
+ * will get re-attached (and re-initialized by the guest) in case it
+ * is still present.
+ *
+ * As the device removal will change the state of other devices (usb
+ * host controller, most likely interrupt controller too) we have to
+ * wait with it until *all* vmstate is loaded. Thus post_load just
+ * kicks a bottom half which then does the actual work.
+ */
+static void usb_host_post_load_bh(void *opaque)
+{
+ USBHostDevice *dev = opaque;
+ USBDevice *udev = USB_DEVICE(dev);
+
+ if (dev->dh != NULL) {
+ usb_host_close(dev);
+ }
+ if (udev->attached) {
+ usb_device_detach(udev);
+ }
+ usb_host_auto_check(NULL);
+}
+
+static int usb_host_post_load(void *opaque, int version_id)
+{
+ USBHostDevice *dev = opaque;
+
+ if (!dev->bh_postld) {
+ dev->bh_postld = qemu_bh_new(usb_host_post_load_bh, dev);
+ }
+ qemu_bh_schedule(dev->bh_postld);
+ return 0;
+}
+
static const VMStateDescription vmstate_usb_host = {
.name = "usb-host",
- .unmigratable = 1,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = usb_host_post_load,
.fields = (VMStateField[]) {
VMSTATE_USB_DEVICE(parent_obj, USBHostDevice),
VMSTATE_END_OF_LIST()
--
1.7.9.7
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 2/4] usb-host: add usb_host_full_speed_compat
2013-05-07 9:50 [Qemu-devel] [PULL for-1.5 0/4] usb patch qeue Gerd Hoffmann
2013-05-07 9:50 ` [Qemu-devel] [PATCH 1/4] usb-host: live migration support for the libusb version Gerd Hoffmann
@ 2013-05-07 9:50 ` Gerd Hoffmann
2013-05-07 9:50 ` [Qemu-devel] [PATCH 3/4] uhci: Use an intermediate buffer for usb packet data Gerd Hoffmann
2013-05-07 9:50 ` [Qemu-devel] [PATCH 4/4] xhci: handle USB_RET_BABBLE Gerd Hoffmann
3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2013-05-07 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Alloes to pass through usb2 devices on usb1 host controllers if possible.
Brings the libusb implementation to feature-parity with the linux usbfs
code, so the usb-host implementation in 1.5 (libusb) doesn't regress
compared to 1.4 (usbfs).
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/host-libusb.c | 40 +++++++++++++++++++++++++++++++++++++---
1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index ee67c4c..f3de459 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -667,6 +667,42 @@ static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p)
/* ------------------------------------------------------------------------ */
+static bool usb_host_full_speed_compat(USBHostDevice *s)
+{
+ struct libusb_config_descriptor *conf;
+ const struct libusb_interface_descriptor *intf;
+ const struct libusb_endpoint_descriptor *endp;
+ uint8_t type;
+ int rc, c, i, a, e;
+
+ for (c = 0;; c++) {
+ rc = libusb_get_config_descriptor(s->dev, c, &conf);
+ if (rc != 0) {
+ break;
+ }
+ for (i = 0; i < conf->bNumInterfaces; i++) {
+ for (a = 0; a < conf->interface[i].num_altsetting; a++) {
+ intf = &conf->interface[i].altsetting[a];
+ for (e = 0; e < intf->bNumEndpoints; e++) {
+ endp = &intf->endpoint[e];
+ type = endp->bmAttributes & 0x3;
+ switch (type) {
+ case 0x01: /* ISO */
+ return false;
+ case 0x03: /* INTERRUPT */
+ if (endp->wMaxPacketSize > 64) {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ }
+ libusb_free_config_descriptor(conf);
+ }
+ return true;
+}
+
static void usb_host_ep_update(USBHostDevice *s)
{
static const char *tname[] = {
@@ -758,11 +794,9 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev)
udev->speed = speed_map[libusb_get_device_speed(dev)];
udev->speedmask = (1 << udev->speed);
-#if 0
- if (udev->speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
+ if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) {
udev->speedmask |= USB_SPEED_MASK_FULL;
}
-#endif
if (s->ddesc.iProduct) {
libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
--
1.7.9.7
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 3/4] uhci: Use an intermediate buffer for usb packet data
2013-05-07 9:50 [Qemu-devel] [PULL for-1.5 0/4] usb patch qeue Gerd Hoffmann
2013-05-07 9:50 ` [Qemu-devel] [PATCH 1/4] usb-host: live migration support for the libusb version Gerd Hoffmann
2013-05-07 9:50 ` [Qemu-devel] [PATCH 2/4] usb-host: add usb_host_full_speed_compat Gerd Hoffmann
@ 2013-05-07 9:50 ` Gerd Hoffmann
2013-05-07 9:50 ` [Qemu-devel] [PATCH 4/4] xhci: handle USB_RET_BABBLE Gerd Hoffmann
3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2013-05-07 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Hans de Goede, Gerd Hoffmann
From: Hans de Goede <hdegoede@redhat.com>
Due to various unfortunate reasons we cannot reliable detect a guest
cancelling a packet as soon as it happens, instead we detect cancels
with some delay.
When packets are handled async, and we directly pass the guest memory for
the packet to the usb-device as iovec, this means that the usb-device can
write to guest-memory which the guest has already re-used for other purposes
-> not good!
This patch fixes this by adding an intermediate buffer and writing back not
only the result, but also the data, of async completed packets when scanning
the schedule.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/hcd-uhci.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index f8c4286..c85b203 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -119,7 +119,8 @@ struct UHCIPCIDeviceClass {
struct UHCIAsync {
USBPacket packet;
- QEMUSGList sgl;
+ uint8_t static_buf[64]; /* 64 bytes is enough, except for isoc packets */
+ uint8_t *buf;
UHCIQueue *queue;
QTAILQ_ENTRY(UHCIAsync) next;
uint32_t td_addr;
@@ -264,7 +265,6 @@ static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr)
async->queue = queue;
async->td_addr = td_addr;
usb_packet_init(&async->packet);
- pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1);
trace_usb_uhci_packet_add(async->queue->token, async->td_addr);
return async;
@@ -274,7 +274,9 @@ static void uhci_async_free(UHCIAsync *async)
{
trace_usb_uhci_packet_del(async->queue->token, async->td_addr);
usb_packet_cleanup(&async->packet);
- qemu_sglist_destroy(&async->sgl);
+ if (async->buf != async->static_buf) {
+ g_free(async->buf);
+ }
g_free(async);
}
@@ -299,7 +301,6 @@ static void uhci_async_cancel(UHCIAsync *async)
async->done);
if (!async->done)
usb_cancel_packet(&async->packet);
- usb_packet_unmap(&async->packet, &async->sgl);
uhci_async_free(async);
}
@@ -774,6 +775,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
*int_mask |= 0x01;
if (pid == USB_TOKEN_IN) {
+ pci_dma_write(&s->dev, td->buffer, async->buf, len);
if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
*int_mask |= 0x02;
/* short packet: do not update QH */
@@ -881,12 +883,17 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
(td->ctrl & TD_CTRL_IOC) != 0);
- qemu_sglist_add(&async->sgl, td->buffer, max_len);
- usb_packet_map(&async->packet, &async->sgl);
+ if (max_len <= sizeof(async->static_buf)) {
+ async->buf = async->static_buf;
+ } else {
+ async->buf = g_malloc(max_len);
+ }
+ usb_packet_addbuf(&async->packet, async->buf, max_len);
switch(pid) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
+ pci_dma_read(&s->dev, td->buffer, async->buf, max_len);
usb_handle_packet(q->ep->dev, &async->packet);
if (async->packet.status == USB_RET_SUCCESS) {
async->packet.actual_length = max_len;
@@ -899,7 +906,6 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
default:
/* invalid pid : frame interrupted */
- usb_packet_unmap(&async->packet, &async->sgl);
uhci_async_free(async);
s->status |= UHCI_STS_HCPERR;
uhci_update_irq(s);
@@ -916,7 +922,6 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
done:
ret = uhci_complete_td(s, td, async, int_mask);
- usb_packet_unmap(&async->packet, &async->sgl);
uhci_async_free(async);
return ret;
}
--
1.7.9.7
^ permalink raw reply related [flat|nested] 5+ messages in thread