usb: bugfix collection.

usb: add cleanup functions for host adapters,
      in preparation for hotplug support.
 usb: add simple qtests for uhci,ohci,xhci.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJUAGpkAAoJEEy22O7T6HE4yrgP/0KoSBWFeBaNmHjsNiZfhn4L
 U88yj3k4Kn5DEXAzy4FG+dKuCcoV1nImvQMWvcY/f4gz+ZJtsIZ/zBfpjVJF9Yhc
 u9hS++oWQqxffxuxqmInnEN9DdybVqeLUlv410k6SR3YTbDY0PeaCMkfgkkI/Gio
 lesobOZxJHhY1jpLTTmeCru1SMGhSP2rUoJs07WAW358V96euhzxIio3CWaX65e9
 VoLd9svMFW1txOoxApMtlydgPUclULNgyytlX2D9QhvOCcBm55YRk2GKfwfmIl94
 3g/kXbu9OmL0NDBeJORRDpjc43p2aWWB+WFTyKOj0/g1poVCiBZta7Qaseap2UJw
 FhD9eeTOh7QrPkqjCvfjQVO4f/V8VfnkDjzhMZWaPIks4/Ja9r/rOA52iG8GVRW6
 i5s69SUXqEmJRTh0jfnOrLoZRWaZAMvxkCPmQ2ktgUy8Kp7gjvhD3QCuj7gmlHP4
 5Itjnxa6gS2YPmB+a+nn/3XLSg/BtpgYc78GvPDRjUGyOrakcDukKQ+woBOJ2pM1
 nZxTT5VDH6FlQalAUNjmcIpq+yV1KWCdD47Ud+Ph2RVlgqE0ODO0m6j9o+zDFi5i
 +fJhhS6o8Zg4FL3QyqSSrD6w/T47ArjwwROhYUPk7+zZxtZ/RcCM6I6ewx2Xcy9M
 PjoifPFx80SK/7Bjyd7p
 =9/+s
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20140829-1' into staging

usb: bugfix collection.
usb: add cleanup functions for host adapters,
     in preparation for hotplug support.
usb: add simple qtests for uhci,ohci,xhci.

# gpg: Signature made Fri 29 Aug 2014 12:56:20 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-usb-20140829-1:
  tests: add xHCI qtest
  tests: add UHCI qtest
  tests: add OHCI qtest
  usb: add usb host adapters exit trace
  usb-xhci: add exit function
  usb-ehci: add ehci-pci device exit function
  usb-ehci: add ehci unrealize funciton
  usb-ehci: add vmstate properity for EHCIState
  usb-uhci: clean up uhci resource when pci-uhci exit
  usb-ohci: add exit function
  usb-ohci: Fix memory leak for ohci timer
  usb: add usb_bus_release function
  Revert "xhci: Fix number of streams allocated when using streams"
  xhci: use (1u << i)
  Fix OHCI ISO TD state never being written back.
  xhci: fix debug print compiling error
  usb: Fix bootindex for portnr > 9

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-08-29 13:08:04 +01:00
commit d9aa688557
14 changed files with 264 additions and 14 deletions

View File

@ -614,7 +614,7 @@ USB
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: hw/usb/*
F: tests/usb-hcd-ehci-test.c
F: tests/usb-*-test.c
VFIO
M: Alex Williamson <alex.williamson@redhat.com>

View File

@ -87,6 +87,13 @@ void usb_bus_new(USBBus *bus, size_t bus_size,
QTAILQ_INSERT_TAIL(&busses, bus, next);
}
void usb_bus_release(USBBus *bus)
{
assert(next_usb_bus > 0);
QTAILQ_REMOVE(&busses, bus, next);
}
USBBus *usb_bus_find(int busnr)
{
USBBus *bus;
@ -589,11 +596,11 @@ static char *usb_get_fw_dev_path(DeviceState *qdev)
nr = strtol(in, &in, 10);
if (in[0] == '.') {
/* some hub between root port and device */
pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
pos += snprintf(fw_path + pos, fw_len - pos, "hub@%lx/", nr);
in++;
} else {
/* the device itself */
pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
pos += snprintf(fw_path + pos, fw_len - pos, "%s@%lx",
qdev_fw_name(qdev), nr);
break;
}

View File

@ -84,6 +84,19 @@ static void usb_ehci_pci_init(Object *obj)
usb_ehci_init(s, DEVICE(obj));
}
static void usb_ehci_pci_exit(PCIDevice *dev)
{
EHCIPCIState *i = PCI_EHCI(dev);
EHCIState *s = &i->ehci;
usb_ehci_unrealize(s, DEVICE(dev), NULL);
if (s->irq) {
g_free(s->irq);
s->irq = NULL;
}
}
static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
uint32_t val, int l)
{
@ -121,6 +134,7 @@ static void ehci_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = usb_ehci_pci_initfn;
k->exit = usb_ehci_pci_exit;
k->class_id = PCI_CLASS_SERIAL_USB;
k->config_write = usb_ehci_pci_write_config;
dc->hotpluggable = false;

View File

@ -2468,7 +2468,34 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
s->device = dev;
qemu_register_reset(ehci_reset, s);
qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
s->vmstate = qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
}
void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp)
{
trace_usb_ehci_unrealize();
if (s->frame_timer) {
timer_del(s->frame_timer);
timer_free(s->frame_timer);
s->frame_timer = NULL;
}
if (s->async_bh) {
qemu_bh_delete(s->async_bh);
}
ehci_queues_rip_all(s, 0);
ehci_queues_rip_all(s, 1);
memory_region_del_subregion(&s->mem, &s->mem_caps);
memory_region_del_subregion(&s->mem, &s->mem_opreg);
memory_region_del_subregion(&s->mem, &s->mem_ports);
usb_bus_release(&s->bus);
if (s->vmstate) {
qemu_del_vm_change_state_handler(s->vmstate);
}
}
void usb_ehci_init(EHCIState *s, DeviceState *dev)

View File

@ -316,12 +316,14 @@ struct EHCIState {
uint32_t async_stepdown;
uint32_t periodic_sched_active;
bool int_req_by_async;
VMChangeStateEntry *vmstate;
};
extern const VMStateDescription vmstate_ehci;
void usb_ehci_init(EHCIState *s, DeviceState *dev);
void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp);
void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp);
#define TYPE_PCI_EHCI "pci-ehci-usb"
#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI)

View File

@ -619,8 +619,8 @@ static inline int ohci_put_td(OHCIState *ohci,
static inline int ohci_put_iso_td(OHCIState *ohci,
dma_addr_t addr, struct ohci_iso_td *td)
{
return put_dwords(ohci, addr, (uint32_t *)td, 4 ||
put_words(ohci, addr + 16, td->offset, 8));
return put_dwords(ohci, addr, (uint32_t *)td, 4) ||
put_words(ohci, addr + 16, td->offset, 8);
}
static inline int ohci_put_hcca(OHCIState *ohci,
@ -1371,8 +1371,10 @@ static int ohci_bus_start(OHCIState *ohci)
/* Stop sending SOF tokens on the bus */
static void ohci_bus_stop(OHCIState *ohci)
{
if (ohci->eof_timer)
if (ohci->eof_timer) {
timer_del(ohci->eof_timer);
timer_free(ohci->eof_timer);
}
ohci->eof_timer = NULL;
}
@ -1952,6 +1954,24 @@ static int usb_ohci_initfn_pci(PCIDevice *dev)
return 0;
}
static void usb_ohci_exit(PCIDevice *dev)
{
OHCIPCIState *ohci = PCI_OHCI(dev);
OHCIState *s = &ohci->state;
ohci_bus_stop(s);
if (s->async_td) {
usb_cancel_packet(&s->usb_packet);
s->async_td = 0;
}
ohci_stop_endpoints(s);
if (!ohci->masterbus) {
usb_bus_release(&s->bus);
}
}
#define TYPE_SYSBUS_OHCI "sysbus-ohci"
#define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI)
@ -2089,6 +2109,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = usb_ohci_initfn_pci;
k->exit = usb_ohci_exit;
k->vendor_id = PCI_VENDOR_ID_APPLE;
k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
k->class_id = PCI_CLASS_SERIAL_USB;

View File

@ -1256,6 +1256,29 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
return usb_uhci_common_initfn(dev);
}
static void usb_uhci_exit(PCIDevice *dev)
{
UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
trace_usb_uhci_exit();
if (s->frame_timer) {
timer_del(s->frame_timer);
timer_free(s->frame_timer);
s->frame_timer = NULL;
}
if (s->bh) {
qemu_bh_delete(s->bh);
}
uhci_async_cancel_all(s);
if (!s->masterbus) {
usb_bus_release(&s->bus);
}
}
static Property uhci_properties[] = {
DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
@ -1272,6 +1295,7 @@ static void uhci_class_init(ObjectClass *klass, void *data)
UHCIInfo *info = data;
k->init = info->initfn ? info->initfn : usb_uhci_common_initfn;
k->exit = info->unplug ? usb_uhci_exit : NULL;
k->vendor_id = info->vendor_id;
k->device_id = info->device_id;
k->revision = info->revision;

View File

@ -1151,7 +1151,7 @@ static void xhci_reset_streams(XHCIEPContext *epctx)
static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base)
{
assert(epctx->pstreams == NULL);
epctx->nr_pstreams = 2 << (epctx->max_pstreams + 1);
epctx->nr_pstreams = 2 << epctx->max_pstreams;
epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base);
}
@ -1180,7 +1180,7 @@ static int xhci_epmask_to_eps_with_streams(XHCIState *xhci,
slot = &xhci->slots[slotid - 1];
for (i = 2, j = 0; i <= 31; i++) {
if (!(epmask & (1 << i))) {
if (!(epmask & (1u << i))) {
continue;
}
@ -1380,14 +1380,11 @@ static void xhci_init_epctx(XHCIEPContext *epctx,
dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type);
epctx->pctx = pctx;
epctx->max_psize = ctx[1]>>16;
epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
epctx->max_pstreams = (ctx[0] >> 10) & 0xf;
epctx->lsa = (ctx[0] >> 15) & 1;
DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
epid/2, epid%2, epctx->max_psize);
if (epctx->max_pstreams) {
xhci_alloc_streams(epctx, dequeue);
} else {
@ -1418,6 +1415,9 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
slot->eps[epid-1] = epctx;
xhci_init_epctx(epctx, pctx, ctx);
DPRINTF("xhci: endpoint %d.%d type is %d, max transaction (burst) "
"size is %d\n", epid/2, epid%2, epctx->type, epctx->max_psize);
epctx->mfindex_last = 0;
epctx->state = EP_RUNNING;
@ -2465,7 +2465,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
res = xhci_alloc_device_streams(xhci, slotid, ictl_ctx[1]);
if (res != CC_SUCCESS) {
for (i = 2; i <= 31; i++) {
if (ictl_ctx[1] & (1 << i)) {
if (ictl_ctx[1] & (1u << i)) {
xhci_disable_ep(xhci, slotid, i);
}
}
@ -3644,6 +3644,43 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
return 0;
}
static void usb_xhci_exit(PCIDevice *dev)
{
int i;
XHCIState *xhci = XHCI(dev);
trace_usb_xhci_exit();
for (i = 0; i < xhci->numslots; i++) {
xhci_disable_slot(xhci, i + 1);
}
if (xhci->mfwrap_timer) {
timer_del(xhci->mfwrap_timer);
timer_free(xhci->mfwrap_timer);
xhci->mfwrap_timer = NULL;
}
memory_region_del_subregion(&xhci->mem, &xhci->mem_cap);
memory_region_del_subregion(&xhci->mem, &xhci->mem_oper);
memory_region_del_subregion(&xhci->mem, &xhci->mem_runtime);
memory_region_del_subregion(&xhci->mem, &xhci->mem_doorbell);
for (i = 0; i < xhci->numports; i++) {
XHCIPort *port = &xhci->ports[i];
memory_region_del_subregion(&xhci->mem, &port->mem);
}
/* destroy msix memory region */
if (dev->msix_table && dev->msix_pba
&& dev->msix_entry_used) {
memory_region_del_subregion(&xhci->mem, &dev->msix_table_mmio);
memory_region_del_subregion(&xhci->mem, &dev->msix_pba_mmio);
}
usb_bus_release(&xhci->bus);
}
static int usb_xhci_post_load(void *opaque, int version_id)
{
XHCIState *xhci = opaque;
@ -3836,6 +3873,7 @@ static void xhci_class_init(ObjectClass *klass, void *data)
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_USB, dc->categories);
k->init = usb_xhci_initfn;
k->exit = usb_xhci_exit;
k->vendor_id = PCI_VENDOR_ID_NEC;
k->device_id = PCI_DEVICE_ID_NEC_UPD720200;
k->class_id = PCI_CLASS_SERIAL_USB;

View File

@ -529,6 +529,7 @@ struct USBBusOps {
void usb_bus_new(USBBus *bus, size_t bus_size,
USBBusOps *ops, DeviceState *host);
void usb_bus_release(USBBus *bus);
USBBus *usb_bus_find(int busnr);
void usb_legacy_register(const char *typename, const char *usbdevice_name,
USBDevice *(*usbdevice_init)(USBBus *bus,

View File

@ -155,11 +155,16 @@ check-qtest-i386-y += tests/i82801b11-test$(EXESUF)
gcov-files-i386-y += hw/pci-bridge/i82801b11.c
check-qtest-i386-y += tests/ioh3420-test$(EXESUF)
gcov-files-i386-y += hw/pci-bridge/ioh3420.c
check-qtest-i386-y += tests/usb-hcd-ohci-test$(EXESUF)
gcov-files-i386-y += hw/usb/hcd-ohci.c
check-qtest-i386-y += tests/usb-hcd-uhci-test$(EXESUF)
gcov-files-i386-y += hw/usb/hcd-uhci.c
check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
gcov-files-i386-y += hw/usb/hcd-ehci.c
gcov-files-i386-y += hw/usb/hcd-uhci.c
gcov-files-i386-y += hw/usb/dev-hid.c
gcov-files-i386-y += hw/usb/dev-storage.c
check-qtest-i386-y += tests/usb-hcd-xhci-test$(EXESUF)
gcov-files-i386-y += hw/usb/hcd-xhci.c
check-qtest-i386-$(CONFIG_LINUX) += tests/vhost-user-test$(EXESUF)
check-qtest-x86_64-y = $(check-qtest-i386-y)
gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
@ -335,7 +340,10 @@ tests/ac97-test$(EXESUF): tests/ac97-test.o
tests/es1370-test$(EXESUF): tests/es1370-test.o
tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o
tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o
tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-pc-obj-y)
tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o
tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y)
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a

35
tests/usb-hcd-ohci-test.c Normal file
View File

@ -0,0 +1,35 @@
/*
* QTest testcase for USB OHCI controller
*
* Copyright (c) 2014 HUAWEI TECHNOLOGIES CO.,LTD.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <glib.h>
#include <string.h>
#include "libqtest.h"
#include "qemu/osdep.h"
static void test_ohci_init(void)
{
qtest_start("-device pci-ohci,id=ohci");
qtest_end();
}
int main(int argc, char **argv)
{
int ret;
g_test_init(&argc, &argv, NULL);
qtest_add_func("/ohci/pci/init", test_ohci_init);
ret = g_test_run();
return ret;
}

35
tests/usb-hcd-uhci-test.c Normal file
View File

@ -0,0 +1,35 @@
/*
* QTest testcase for USB UHCI controller
*
* Copyright (c) 2014 HUAWEI TECHNOLOGIES CO.,LTD.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <glib.h>
#include <string.h>
#include "libqtest.h"
#include "qemu/osdep.h"
static void test_uhci_init(void)
{
qtest_start("-device piix3-usb-uhci,id=uhci");
qtest_end();
}
int main(int argc, char **argv)
{
int ret;
g_test_init(&argc, &argv, NULL);
qtest_add_func("/uhci/pci/init", test_uhci_init);
ret = g_test_run();
return ret;
}

35
tests/usb-hcd-xhci-test.c Normal file
View File

@ -0,0 +1,35 @@
/*
* QTest testcase for USB xHCI controller
*
* Copyright (c) 2014 HUAWEI TECHNOLOGIES CO.,LTD.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <glib.h>
#include <string.h>
#include "libqtest.h"
#include "qemu/osdep.h"
static void test_xhci_init(void)
{
qtest_start("-device nec-usb-xhci,id=xhci");
qtest_end();
}
int main(int argc, char **argv)
{
int ret;
g_test_init(&argc, &argv, NULL);
qtest_add_func("/xhci/pci/init", test_xhci_init);
ret = g_test_run();
return ret;
}

View File

@ -297,6 +297,7 @@ usb_port_release(int bus, const char *port) "bus %d, port %s"
# hw/usb/hcd-ehci.c
usb_ehci_reset(void) "=== RESET ==="
usb_ehci_unrealize(void) "=== UNREALIZE ==="
usb_ehci_opreg_read(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
usb_ehci_opreg_write(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x"
usb_ehci_opreg_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
@ -329,6 +330,7 @@ usb_ehci_dma_error(void) ""
# hw/usb/hcd-uhci.c
usb_uhci_reset(void) "=== RESET ==="
usb_uhci_exit(void) "=== EXIT ==="
usb_uhci_schedule_start(void) ""
usb_uhci_schedule_stop(void) ""
usb_uhci_frame_start(uint32_t num) "nr %d"
@ -358,6 +360,7 @@ usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
# hw/usb/hcd-xhci.c
usb_xhci_reset(void) "=== RESET ==="
usb_xhci_exit(void) "=== EXIT ==="
usb_xhci_run(void) ""
usb_xhci_stop(void) ""
usb_xhci_cap_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x"