From 3bf2b3a17274e5e3ca41ba01a677ea35e060febc Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 29 Jul 2016 08:59:29 +0200 Subject: wxx: Fix compiler warning for host-libusb.c The local variable i is unsed for Windows. Signed-off-by: Stefan Weil Message-id: 1469775569-7869-1-git-send-email-sw@weilnetz.de Signed-off-by: Gerd Hoffmann --- hw/usb/host-libusb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw/usb') diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index da59c29..9af0580 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -235,7 +235,7 @@ static int usb_host_init(void) #ifndef CONFIG_WIN32 const struct libusb_pollfd **poll; #endif - int i, rc; + int rc; if (ctx) { return 0; @@ -253,6 +253,7 @@ static int usb_host_init(void) ctx); poll = libusb_get_pollfds(ctx); if (poll) { + int i; for (i = 0; poll[i] != NULL; i++) { usb_host_add_fd(poll[i]->fd, poll[i]->events, ctx); } -- cgit v1.1 From c16e366464a1884c355e85878874afffa790ecbf Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 29 Jul 2016 08:55:31 +0200 Subject: wxx: Fix compilation of host-libusb.c libusb.h uses the WINAPI calling convention for all function callbacks. Cross compilation with Mingw-w64 on Cygwin fails when this calling convention is missing. Signed-off-by: Stefan Weil Message-id: 1469775331-7468-1-git-send-email-sw@weilnetz.de Signed-off-by: Gerd Hoffmann --- hw/usb/host-libusb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'hw/usb') diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 9af0580..e94672c 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -359,7 +359,7 @@ static USBHostRequest *usb_host_req_find(USBHostDevice *s, USBPacket *p) return NULL; } -static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer) +static void LIBUSB_CALL usb_host_req_complete_ctrl(struct libusb_transfer *xfer) { USBHostRequest *r = xfer->user_data; USBHostDevice *s = r->host; @@ -392,7 +392,7 @@ out: } } -static void usb_host_req_complete_data(struct libusb_transfer *xfer) +static void LIBUSB_CALL usb_host_req_complete_data(struct libusb_transfer *xfer) { USBHostRequest *r = xfer->user_data; USBHostDevice *s = r->host; @@ -448,7 +448,8 @@ static void usb_host_req_abort(USBHostRequest *r) /* ------------------------------------------------------------------------ */ -static void usb_host_req_complete_iso(struct libusb_transfer *transfer) +static void LIBUSB_CALL +usb_host_req_complete_iso(struct libusb_transfer *transfer) { USBHostIsoXfer *xfer = transfer->user_data; -- cgit v1.1 From 72aa364b1d9daa889bb5898ea4aded9d27fd1c96 Mon Sep 17 00:00:00 2001 From: Evgeny Yakovlev Date: Wed, 27 Jul 2016 19:55:20 +0300 Subject: ehci: faster frame index calculation for skipped frames ehci_update_frindex takes time linearly proportional to a number of uframes to calculate new frame index and raise FLR interrupts, which is a problem for large amounts of uframes. If we experience large delays between echi timer callbacks (i.e. because other periodic handlers have taken a lot of time to complete) we get a lot of skipped frames which then delay ehci timer callback more and this leads to deadlocking the system when ehci schedules next callback to be too soon. Observable behaviour is qemu consuming 100% host CPU time while guest is unresponsive. This misbehavior could happen for a while and QEMU does not get out from this state automatically without the patch. This change makes ehci_update_frindex execute in constant time. Signed-off-by: Evgeny Yakovlev Signed-off-by: Denis V. Lunev Message-id: 1469638520-32706-1-git-send-email-den@openvz.org CC: Gerd Hoffmann Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'hw/usb') diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 43a8f7a..b093db7 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2206,29 +2206,28 @@ static void ehci_advance_periodic_state(EHCIState *ehci) static void ehci_update_frindex(EHCIState *ehci, int uframes) { - int i; - if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) { return; } - for (i = 0; i < uframes; i++) { - ehci->frindex++; - - if (ehci->frindex == 0x00002000) { - ehci_raise_irq(ehci, USBSTS_FLR); - } + /* Generate FLR interrupt if frame index rolls over 0x2000 */ + if ((ehci->frindex % 0x2000) + uframes >= 0x2000) { + ehci_raise_irq(ehci, USBSTS_FLR); + } - if (ehci->frindex == 0x00004000) { - ehci_raise_irq(ehci, USBSTS_FLR); - ehci->frindex = 0; - if (ehci->usbsts_frindex >= 0x00004000) { - ehci->usbsts_frindex -= 0x00004000; - } else { - ehci->usbsts_frindex = 0; - } + /* How many times will frindex roll over 0x4000 with this frame count? + * usbsts_frindex is decremented by 0x4000 on rollover until it reaches 0 + */ + int rollovers = (ehci->frindex + uframes) / 0x4000; + if (rollovers > 0) { + if (ehci->usbsts_frindex >= (rollovers * 0x4000)) { + ehci->usbsts_frindex -= 0x4000 * rollovers; + } else { + ehci->usbsts_frindex = 0; } } + + ehci->frindex = (ehci->frindex + uframes) % 0x4000; } static void ehci_frame_timer(void *opaque) -- cgit v1.1 From 80440ea033b02d9c7330d507daf41d4bf8a8c058 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Tue, 2 Aug 2016 14:14:04 +0200 Subject: xen: drain submit queue in xen-usb before removing device When unplugging a device in the Xen pvusb backend drain the submit queue before deallocation of the control structures. Otherwise there will be bogus memory accesses when I/O contracts are finished. Correlated to this issue is the handling of cancel requests: a packet cancelled will still lead to the call of complete, so add a flag to the request indicating it should be just dropped on complete. Signed-off-by: Juergen Gross Acked-by: Anthony PERARD Message-id: 1470140044-16492-3-git-send-email-jgross@suse.com Signed-off-by: Gerd Hoffmann --- hw/usb/xen-usb.c | 96 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 33 deletions(-) (limited to 'hw/usb') diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 7992456..174d715 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -90,6 +90,8 @@ struct usbback_req { void *buffer; void *isoc_buffer; struct libusb_transfer *xfer; + + bool cancelled; }; struct usbback_hotplug { @@ -301,20 +303,23 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status, usbback_req->isoc_buffer = NULL; } - res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); - res->id = usbback_req->req.id; - res->status = status; - res->actual_length = actual_length; - res->error_count = error_count; - res->start_frame = 0; - usbif->urb_ring.rsp_prod_pvt++; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); - - if (notify) { - xen_be_send_notify(xendev); + if (usbif->urb_sring) { + res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); + res->id = usbback_req->req.id; + res->status = status; + res->actual_length = actual_length; + res->error_count = error_count; + res->start_frame = 0; + usbif->urb_ring.rsp_prod_pvt++; + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); + + if (notify) { + xen_be_send_notify(xendev); + } } - usbback_put_req(usbback_req); + if (!usbback_req->cancelled) + usbback_put_req(usbback_req); } static void usbback_do_response_ret(struct usbback_req *usbback_req, @@ -366,15 +371,14 @@ static void usbback_set_address(struct usbback_info *usbif, } } -static bool usbback_cancel_req(struct usbback_req *usbback_req) +static void usbback_cancel_req(struct usbback_req *usbback_req) { - bool ret = false; - if (usb_packet_is_inflight(&usbback_req->packet)) { usb_cancel_packet(&usbback_req->packet); - ret = true; + QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); + usbback_req->cancelled = true; + usbback_do_response_ret(usbback_req, -EPROTO); } - return ret; } static void usbback_process_unlink_req(struct usbback_req *usbback_req) @@ -391,7 +395,7 @@ static void usbback_process_unlink_req(struct usbback_req *usbback_req) devnum = usbif_pipedevice(usbback_req->req.pipe); if (unlikely(devnum == 0)) { usbback_req->stub = usbif->ports + - usbif_pipeportnum(usbback_req->req.pipe); + usbif_pipeportnum(usbback_req->req.pipe) - 1; if (unlikely(!usbback_req->stub)) { ret = -ENODEV; goto fail_response; @@ -406,9 +410,7 @@ static void usbback_process_unlink_req(struct usbback_req *usbback_req) QTAILQ_FOREACH(unlink_req, &usbback_req->stub->submit_q, q) { if (unlink_req->req.id == id) { - if (usbback_cancel_req(unlink_req)) { - usbback_do_response_ret(unlink_req, -EPROTO); - } + usbback_cancel_req(unlink_req); break; } } @@ -681,6 +683,33 @@ static void usbback_hotplug_enq(struct usbback_info *usbif, unsigned port) usbback_hotplug_notify(usbif); } +static void usbback_portid_drain(struct usbback_info *usbif, unsigned port) +{ + struct usbback_req *req, *tmp; + bool sched = false; + + QTAILQ_FOREACH_SAFE(req, &usbif->ports[port - 1].submit_q, q, tmp) { + usbback_cancel_req(req); + sched = true; + } + + if (sched) { + qemu_bh_schedule(usbif->bh); + } +} + +static void usbback_portid_detach(struct usbback_info *usbif, unsigned port) +{ + if (!usbif->ports[port - 1].attached) { + return; + } + + usbif->ports[port - 1].speed = USBIF_SPEED_NONE; + usbif->ports[port - 1].attached = false; + usbback_portid_drain(usbif, port); + usbback_hotplug_enq(usbif, port); +} + static void usbback_portid_remove(struct usbback_info *usbif, unsigned port) { USBPort *p; @@ -694,9 +723,7 @@ static void usbback_portid_remove(struct usbback_info *usbif, unsigned port) object_unparent(OBJECT(usbif->ports[port - 1].dev)); usbif->ports[port - 1].dev = NULL; - usbif->ports[port - 1].speed = USBIF_SPEED_NONE; - usbif->ports[port - 1].attached = false; - usbback_hotplug_enq(usbif, port); + usbback_portid_detach(usbif, port); TR_BUS(&usbif->xendev, "port %d removed\n", port); } @@ -801,7 +828,6 @@ static void usbback_process_port(struct usbback_info *usbif, unsigned port) static void usbback_disconnect(struct XenDevice *xendev) { struct usbback_info *usbif; - struct usbback_req *req, *tmp; unsigned int i; TR_BUS(xendev, "start\n"); @@ -820,11 +846,8 @@ static void usbback_disconnect(struct XenDevice *xendev) } for (i = 0; i < usbif->num_ports; i++) { - if (!usbif->ports[i].dev) { - continue; - } - QTAILQ_FOREACH_SAFE(req, &usbif->ports[i].submit_q, q, tmp) { - usbback_cancel_req(req); + if (usbif->ports[i].dev) { + usbback_portid_drain(usbif, i + 1); } } @@ -944,8 +967,7 @@ static void xen_bus_detach(USBPort *port) usbif = port->opaque; TR_BUS(&usbif->xendev, "\n"); - usbif->ports[port->index].attached = false; - usbback_hotplug_enq(usbif, port->index + 1); + usbback_portid_detach(usbif, port->index + 1); } static void xen_bus_child_detach(USBPort *port, USBDevice *child) @@ -958,9 +980,16 @@ static void xen_bus_child_detach(USBPort *port, USBDevice *child) static void xen_bus_complete(USBPort *port, USBPacket *packet) { + struct usbback_req *usbback_req; struct usbback_info *usbif; - usbif = port->opaque; + usbback_req = container_of(packet, struct usbback_req, packet); + if (usbback_req->cancelled) { + g_free(usbback_req); + return; + } + + usbif = usbback_req->usbif; TR_REQ(&usbif->xendev, "\n"); usbback_packet_complete(packet); } @@ -1037,6 +1066,7 @@ static int usbback_free(struct XenDevice *xendev) } usb_bus_release(&usbif->bus); + object_unparent(OBJECT(&usbif->bus)); TR_BUS(xendev, "finished\n"); -- cgit v1.1