diff --git a/0111-usb-redir-Add-flow-control-support.patch b/0111-usb-redir-Add-flow-control-support.patch index 3edcd1a..76b5ca5 100644 --- a/0111-usb-redir-Add-flow-control-support.patch +++ b/0111-usb-redir-Add-flow-control-support.patch @@ -41,7 +41,7 @@ index ecb2cd4..1460515 100644 } /* -@@ -892,10 +902,22 @@ static void usbredir_chardev_event(void *opaque, int event) +@@ -892,10 +902,18 @@ static void usbredir_chardev_event(void *opaque, int event) } } @@ -49,10 +49,6 @@ index ecb2cd4..1460515 100644 +{ + USBRedirDevice *dev = opaque; + -+ if (dev->parser == NULL) { -+ /* usbredir_open_close_bh hasn't handled the open event yet */ -+ return; -+ } + usbredirparser_do_write(dev->parser); +} + diff --git a/0215-qxl-dont-update-invalid-area.patch b/0215-qxl-dont-update-invalid-area.patch deleted file mode 100644 index 8739272..0000000 --- a/0215-qxl-dont-update-invalid-area.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 6f1652c4412ab60c7f456100143c519d124a895c Mon Sep 17 00:00:00 2001 -From: Dunrong Huang -Date: Fri, 31 Aug 2012 00:44:44 +0800 -Subject: [PATCH 215/215] qxl: dont update invalid area - -This patch fixes the following error: - -$ ~/usr/bin/qemu-system-x86_64 -enable-kvm -m 1024 -spice port=5900,disable-ticketing -vga qxl -cdrom ~/Images/linuxmint-13-mate-dvd-32bit.iso -(/home/mathslinux/usr/bin/qemu-system-x86_64:10068): SpiceWorker-CRITICAL **: red_worker.c:4599:red_update_area: condition `area->left >= 0 && area->top >= 0 && area->left < area->right && area->top < area->bottom' failed -Aborted - -spice server terminates QEMU process if we pass invalid area to it, -so dont update those invalid areas. - -Signed-off-by: Dunrong Huang -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index b726c19..045432e 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1470,6 +1470,13 @@ async_common: - return; - } - -+ if (update.left < 0 || update.top < 0 || update.left >= update.right || -+ update.top >= update.bottom) { -+ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " -+ "invalid area(%d,%d,%d,%d)\n", update.left, -+ update.right, update.top, update.bottom); -+ break; -+ } - if (async == QXL_ASYNC) { - cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_UPDATE_AREA_ASYNC); --- -1.7.12 - diff --git a/0215-spice-switch-to-queue-for-vga-mode-updates.patch b/0215-spice-switch-to-queue-for-vga-mode-updates.patch new file mode 100644 index 0000000..9bd3562 --- /dev/null +++ b/0215-spice-switch-to-queue-for-vga-mode-updates.patch @@ -0,0 +1,138 @@ +From 20b7c4b95c7f0c93000a68779e9cb9e63cff68da Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 5 Sep 2012 08:25:08 +0200 +Subject: [PATCH 215/293] spice: switch to queue for vga mode updates + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 6 +++--- + ui/spice-display.c | 25 ++++++++++++++----------- + ui/spice-display.h | 3 ++- + 3 files changed, 19 insertions(+), 15 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index b726c19..833cd77 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -597,9 +597,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + case QXL_MODE_VGA: + ret = false; + qemu_mutex_lock(&qxl->ssd.lock); +- if (qxl->ssd.update != NULL) { +- update = qxl->ssd.update; +- qxl->ssd.update = NULL; ++ update = QTAILQ_FIRST(&qxl->ssd.updates); ++ if (update != NULL) { ++ QTAILQ_REMOVE(&qxl->ssd.updates, update, next); + *ext = update->ext; + ret = true; + } +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 99bc665..59c5fd7 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -164,7 +164,7 @@ int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) + #endif + } + +-static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) ++static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + { + SimpleSpiceUpdate *update; + QXLDrawable *drawable; +@@ -175,7 +175,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + struct timespec time_space; + + if (qemu_spice_rect_is_empty(&ssd->dirty)) { +- return NULL; ++ return; + }; + + trace_qemu_spice_create_update( +@@ -239,7 +239,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + cmd->data = (uintptr_t)drawable; + + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); +- return update; ++ QTAILQ_INSERT_TAIL(&ssd->updates, update, next); + } + + /* +@@ -315,6 +315,7 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) + { + ssd->ds = ds; + qemu_mutex_init(&ssd->lock); ++ QTAILQ_INIT(&ssd->updates); + ssd->mouse_x = -1; + ssd->mouse_y = -1; + if (ssd->num_surfaces == 0) { +@@ -345,6 +346,8 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + + void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) + { ++ SimpleSpiceUpdate *update; ++ + dprint(1, "%s:\n", __FUNCTION__); + + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); +@@ -352,9 +355,9 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) + ssd->conv = NULL; + + qemu_mutex_lock(&ssd->lock); +- if (ssd->update != NULL) { +- qemu_spice_destroy_update(ssd, ssd->update); +- ssd->update = NULL; ++ while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { ++ QTAILQ_REMOVE(&ssd->updates, update, next); ++ qemu_spice_destroy_update(ssd, update); + } + qemu_mutex_unlock(&ssd->lock); + qemu_spice_destroy_host_primary(ssd); +@@ -384,8 +387,8 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) + vga_hw_update(); + + qemu_mutex_lock(&ssd->lock); +- if (ssd->update == NULL) { +- ssd->update = qemu_spice_create_update(ssd); ++ if (QTAILQ_EMPTY(&ssd->updates)) { ++ qemu_spice_create_update(ssd); + ssd->notify++; + } + qemu_spice_cursor_refresh_unlocked(ssd); +@@ -442,9 +445,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + dprint(3, "%s:\n", __FUNCTION__); + + qemu_mutex_lock(&ssd->lock); +- if (ssd->update != NULL) { +- update = ssd->update; +- ssd->update = NULL; ++ update = QTAILQ_FIRST(&ssd->updates); ++ if (update != NULL) { ++ QTAILQ_REMOVE(&ssd->updates, update, next); + *ext = update->ext; + ret = true; + } +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 512ab78..3fcb6fe 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -92,7 +92,7 @@ struct SimpleSpiceDisplay { + * to them must be protected by the lock. + */ + QemuMutex lock; +- SimpleSpiceUpdate *update; ++ QTAILQ_HEAD(, SimpleSpiceUpdate) updates; + QEMUCursor *cursor; + int mouse_x, mouse_y; + }; +@@ -102,6 +102,7 @@ struct SimpleSpiceUpdate { + QXLImage image; + QXLCommandExt ext; + uint8_t *bitmap; ++ QTAILQ_ENTRY(SimpleSpiceUpdate) next; + }; + + int qemu_spice_rect_is_empty(const QXLRect* r); +-- +1.7.12 + diff --git a/0216-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch b/0216-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch deleted file mode 100644 index 3391970..0000000 --- a/0216-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 68d246d6a904e0a851c521a08a18187598e1c696 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 7 Sep 2012 21:29:22 +0200 -Subject: [PATCH] qxl: Ignore set_client_capabilities pre/post migrate - -The recent introduction of set_client_capabilities has broken -(seamless) migration by trying to call qxl_send_events pre (seamless -incoming) and post (*) migration, triggering the following assert: -qxl_send_events: Assertion `qemu_spice_display_is_running(&d->ssd)' failed. - -The solution is easy, pre migration the guest will have already received -the client caps on the migration source side, and post migration there no -longer is a guest, so we can simply ignore the set_client_capabilities call -in both those scenarios. - -*) Post migration, so not fatal for to the migration itself, but still a crash - -Signed-off-by: Hans de Goede ---- - hw/qxl.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 045432e..1b400f1 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -953,6 +953,11 @@ static void interface_set_client_capabilities(QXLInstance *sin, - { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - -+ if (runstate_check(RUN_STATE_INMIGRATE) || -+ runstate_check(RUN_STATE_POSTMIGRATE)) { -+ return; -+ } -+ - qxl->shadow_rom.client_present = client_present; - memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); - qxl->rom->client_present = client_present; --- -1.7.12 - diff --git a/0216-spice-split-qemu_spice_create_update.patch b/0216-spice-split-qemu_spice_create_update.patch new file mode 100644 index 0000000..711382c --- /dev/null +++ b/0216-spice-split-qemu_spice_create_update.patch @@ -0,0 +1,94 @@ +From a754b60d7602dae18120ab014735927058e89983 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 5 Sep 2012 08:52:23 +0200 +Subject: [PATCH 216/293] spice: split qemu_spice_create_update + +Creating one function which creates a single update for a given +rectangle. And one (for now) pretty simple wrapper around it to +queue up screen updates for the dirty region. + +[ v2: also update bounding box ] + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 31 ++++++++++++++++++------------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 59c5fd7..6f68f28 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -164,7 +164,8 @@ int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) + #endif + } + +-static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) ++static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, ++ QXLRect *rect) + { + SimpleSpiceUpdate *update; + QXLDrawable *drawable; +@@ -174,24 +175,20 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + int by, bw, bh; + struct timespec time_space; + +- if (qemu_spice_rect_is_empty(&ssd->dirty)) { +- return; +- }; +- + trace_qemu_spice_create_update( +- ssd->dirty.left, ssd->dirty.right, +- ssd->dirty.top, ssd->dirty.bottom); ++ rect->left, rect->right, ++ rect->top, rect->bottom); + + update = g_malloc0(sizeof(*update)); + drawable = &update->drawable; + image = &update->image; + cmd = &update->ext.cmd; + +- bw = ssd->dirty.right - ssd->dirty.left; +- bh = ssd->dirty.bottom - ssd->dirty.top; ++ bw = rect->right - rect->left; ++ bh = rect->bottom - rect->top; + update->bitmap = g_malloc(bw * bh * 4); + +- drawable->bbox = ssd->dirty; ++ drawable->bbox = *rect; + drawable->clip.type = SPICE_CLIP_TYPE_NONE; + drawable->effect = QXL_EFFECT_OPAQUE; + drawable->release_info.id = (uintptr_t)update; +@@ -226,8 +223,8 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + } + + src = ds_get_data(ssd->ds) + +- ssd->dirty.top * ds_get_linesize(ssd->ds) + +- ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds); ++ rect->top * ds_get_linesize(ssd->ds) + ++ rect->left * ds_get_bytes_per_pixel(ssd->ds); + dst = update->bitmap; + for (by = 0; by < bh; by++) { + qemu_pf_conv_run(ssd->conv, dst, src, bw); +@@ -238,10 +235,18 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + cmd->type = QXL_CMD_DRAW; + cmd->data = (uintptr_t)drawable; + +- memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + QTAILQ_INSERT_TAIL(&ssd->updates, update, next); + } + ++static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) ++{ ++ if (qemu_spice_rect_is_empty(&ssd->dirty)) { ++ return; ++ }; ++ qemu_spice_create_one_update(ssd, &ssd->dirty); ++ memset(&ssd->dirty, 0, sizeof(ssd->dirty)); ++} ++ + /* + * Called from spice server thread context (via interface_release_ressource) + * We do *not* hold the global qemu mutex here, so extra care is needed +-- +1.7.12 + diff --git a/0217-spice-add-screen-mirror.patch b/0217-spice-add-screen-mirror.patch new file mode 100644 index 0000000..5898ba8 --- /dev/null +++ b/0217-spice-add-screen-mirror.patch @@ -0,0 +1,98 @@ +From d7080640a03a1c7739eb730eaec0c63e7e12cdb6 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 5 Sep 2012 09:35:57 +0200 +Subject: [PATCH 217/293] spice: add screen mirror + +Create a screen mirror, keep there a copy of the most recent update +passed on to spice-server. + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 32 ++++++++++++++++++++++---------- + ui/spice-display.h | 1 + + 2 files changed, 23 insertions(+), 10 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 6f68f28..973cd53 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -171,8 +171,8 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, + QXLDrawable *drawable; + QXLImage *image; + QXLCommand *cmd; +- uint8_t *src, *dst; +- int by, bw, bh; ++ uint8_t *src, *mirror, *dst; ++ int by, bw, bh, offset, bytes; + struct timespec time_space; + + trace_qemu_spice_create_update( +@@ -216,19 +216,18 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, + image->bitmap.palette = 0; + image->bitmap.format = SPICE_BITMAP_FMT_32BIT; + +- if (ssd->conv == NULL) { +- PixelFormat dst = qemu_default_pixelformat(32); +- ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); +- assert(ssd->conv); +- } +- +- src = ds_get_data(ssd->ds) + ++ offset = + rect->top * ds_get_linesize(ssd->ds) + + rect->left * ds_get_bytes_per_pixel(ssd->ds); ++ bytes = ds_get_bytes_per_pixel(ssd->ds) * bw; ++ src = ds_get_data(ssd->ds) + offset; ++ mirror = ssd->ds_mirror + offset; + dst = update->bitmap; + for (by = 0; by < bh; by++) { +- qemu_pf_conv_run(ssd->conv, dst, src, bw); ++ memcpy(mirror, src, bytes); ++ qemu_pf_conv_run(ssd->conv, dst, mirror, bw); + src += ds_get_linesize(ssd->ds); ++ mirror += ds_get_linesize(ssd->ds); + dst += image->bitmap.stride; + } + +@@ -243,6 +242,17 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + if (qemu_spice_rect_is_empty(&ssd->dirty)) { + return; + }; ++ ++ if (ssd->conv == NULL) { ++ PixelFormat dst = qemu_default_pixelformat(32); ++ ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); ++ assert(ssd->conv); ++ } ++ if (ssd->ds_mirror == NULL) { ++ int size = ds_get_height(ssd->ds) * ds_get_linesize(ssd->ds); ++ ssd->ds_mirror = g_malloc0(size); ++ } ++ + qemu_spice_create_one_update(ssd, &ssd->dirty); + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + } +@@ -358,6 +368,8 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + qemu_pf_conv_put(ssd->conv); + ssd->conv = NULL; ++ g_free(ssd->ds_mirror); ++ ssd->ds_mirror = NULL; + + qemu_mutex_lock(&ssd->lock); + while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 3fcb6fe..dea41c1 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -72,6 +72,7 @@ typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; + + struct SimpleSpiceDisplay { + DisplayState *ds; ++ uint8_t *ds_mirror; + void *buf; + int bufsize; + QXLWorker *worker; +-- +1.7.12 + diff --git a/0218-spice-send-updates-only-for-changed-screen-content.patch b/0218-spice-send-updates-only-for-changed-screen-content.patch new file mode 100644 index 0000000..5b63fec --- /dev/null +++ b/0218-spice-send-updates-only-for-changed-screen-content.patch @@ -0,0 +1,93 @@ +From e503ba260e585c9ee56f44ae5b8da51643776369 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 5 Sep 2012 10:41:42 +0200 +Subject: [PATCH 218/293] spice: send updates only for changed screen content + +when creating screen updates go compare the current guest screen +against the mirror (which holds the most recent update sent), then +only create updates for the screen areas which did actually change. + +[ v2: drop redundant qemu_spice_create_one_update call ] + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 55 insertions(+), 1 deletion(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 973cd53..d062765 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -239,6 +239,13 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, + + static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + { ++ static const int blksize = 32; ++ int blocks = (ds_get_width(ssd->ds) + blksize - 1) / blksize; ++ int dirty_top[blocks]; ++ int y, yoff, x, xoff, blk, bw; ++ int bpp = ds_get_bytes_per_pixel(ssd->ds); ++ uint8_t *guest, *mirror; ++ + if (qemu_spice_rect_is_empty(&ssd->dirty)) { + return; + }; +@@ -253,7 +260,54 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + ssd->ds_mirror = g_malloc0(size); + } + +- qemu_spice_create_one_update(ssd, &ssd->dirty); ++ for (blk = 0; blk < blocks; blk++) { ++ dirty_top[blk] = -1; ++ } ++ ++ guest = ds_get_data(ssd->ds); ++ mirror = ssd->ds_mirror; ++ for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { ++ yoff = y * ds_get_linesize(ssd->ds); ++ for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { ++ xoff = x * bpp; ++ blk = x / blksize; ++ bw = MIN(blksize, ssd->dirty.right - x); ++ if (memcmp(guest + yoff + xoff, ++ mirror + yoff + xoff, ++ bw * bpp) == 0) { ++ if (dirty_top[blk] != -1) { ++ QXLRect update = { ++ .top = dirty_top[blk], ++ .bottom = y, ++ .left = x, ++ .right = x + bw, ++ }; ++ qemu_spice_create_one_update(ssd, &update); ++ dirty_top[blk] = -1; ++ } ++ } else { ++ if (dirty_top[blk] == -1) { ++ dirty_top[blk] = y; ++ } ++ } ++ } ++ } ++ ++ for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { ++ blk = x / blksize; ++ bw = MIN(blksize, ssd->dirty.right - x); ++ if (dirty_top[blk] != -1) { ++ QXLRect update = { ++ .top = dirty_top[blk], ++ .bottom = ssd->dirty.bottom, ++ .left = x, ++ .right = x + bw, ++ }; ++ qemu_spice_create_one_update(ssd, &update); ++ dirty_top[blk] = -1; ++ } ++ } ++ + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + } + +-- +1.7.12 + diff --git a/0219-qxl-dont-update-invalid-area.patch b/0219-qxl-dont-update-invalid-area.patch new file mode 100644 index 0000000..8739272 --- /dev/null +++ b/0219-qxl-dont-update-invalid-area.patch @@ -0,0 +1,41 @@ +From 6f1652c4412ab60c7f456100143c519d124a895c Mon Sep 17 00:00:00 2001 +From: Dunrong Huang +Date: Fri, 31 Aug 2012 00:44:44 +0800 +Subject: [PATCH 215/215] qxl: dont update invalid area + +This patch fixes the following error: + +$ ~/usr/bin/qemu-system-x86_64 -enable-kvm -m 1024 -spice port=5900,disable-ticketing -vga qxl -cdrom ~/Images/linuxmint-13-mate-dvd-32bit.iso +(/home/mathslinux/usr/bin/qemu-system-x86_64:10068): SpiceWorker-CRITICAL **: red_worker.c:4599:red_update_area: condition `area->left >= 0 && area->top >= 0 && area->left < area->right && area->top < area->bottom' failed +Aborted + +spice server terminates QEMU process if we pass invalid area to it, +so dont update those invalid areas. + +Signed-off-by: Dunrong Huang +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index b726c19..045432e 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1470,6 +1470,13 @@ async_common: + return; + } + ++ if (update.left < 0 || update.top < 0 || update.left >= update.right || ++ update.top >= update.bottom) { ++ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " ++ "invalid area(%d,%d,%d,%d)\n", update.left, ++ update.right, update.top, update.bottom); ++ break; ++ } + if (async == QXL_ASYNC) { + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_UPDATE_AREA_ASYNC); +-- +1.7.12 + diff --git a/0220-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch b/0220-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch new file mode 100644 index 0000000..3391970 --- /dev/null +++ b/0220-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch @@ -0,0 +1,41 @@ +From 68d246d6a904e0a851c521a08a18187598e1c696 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 7 Sep 2012 21:29:22 +0200 +Subject: [PATCH] qxl: Ignore set_client_capabilities pre/post migrate + +The recent introduction of set_client_capabilities has broken +(seamless) migration by trying to call qxl_send_events pre (seamless +incoming) and post (*) migration, triggering the following assert: +qxl_send_events: Assertion `qemu_spice_display_is_running(&d->ssd)' failed. + +The solution is easy, pre migration the guest will have already received +the client caps on the migration source side, and post migration there no +longer is a guest, so we can simply ignore the set_client_capabilities call +in both those scenarios. + +*) Post migration, so not fatal for to the migration itself, but still a crash + +Signed-off-by: Hans de Goede +--- + hw/qxl.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 045432e..1b400f1 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -953,6 +953,11 @@ static void interface_set_client_capabilities(QXLInstance *sin, + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + ++ if (runstate_check(RUN_STATE_INMIGRATE) || ++ runstate_check(RUN_STATE_POSTMIGRATE)) { ++ return; ++ } ++ + qxl->shadow_rom.client_present = client_present; + memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); + qxl->rom->client_present = client_present; +-- +1.7.12 + diff --git a/0221-qxl-better-cleanup-for-surface-destroy.patch b/0221-qxl-better-cleanup-for-surface-destroy.patch new file mode 100644 index 0000000..d24e093 --- /dev/null +++ b/0221-qxl-better-cleanup-for-surface-destroy.patch @@ -0,0 +1,32 @@ +From 2315ba0b57785d788828e6871e528c9ab368068f Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Tue, 11 Sep 2012 10:09:58 +0300 +Subject: [PATCH 221/293] qxl: better cleanup for surface destroy + +Add back a call to qxl_spice_destroy_surface_wait_complete() in qxl_spice_destroy_surface_wait(), +that was removed by commit c480bb7da465186b84d8427e068ef7502e47ffbf + +It is needed to complete surface-removal cleanup, for non async. +For async, qxl_spice_destroy_surface_wait_complete is called upon operation completion. + +Signed-off-by: Uri Lublin +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 144a002..9f06f5e 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -201,6 +201,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); ++ qxl_spice_destroy_surface_wait_complete(qxl, id); + } + } + +-- +1.7.12 + diff --git a/0222-hw-qxl-tracing-fixes.patch b/0222-hw-qxl-tracing-fixes.patch new file mode 100644 index 0000000..2feba9d --- /dev/null +++ b/0222-hw-qxl-tracing-fixes.patch @@ -0,0 +1,96 @@ +From b1b9a04abd4cc461e507091fadea866788d4a60a Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 12 Sep 2012 16:13:26 +0300 +Subject: [PATCH 222/293] hw/qxl: tracing fixes + +Add two new trace events: +qxl_send_events(int qid, uint32_t events) "%d %d" +qxl_set_guest_bug(int qid) "%d" + +Change qxl_io_unexpected_vga_mode parameters to be equivalent to those +of qxl_io_write for easier grouping under a single systemtap probe. + +Change d to qxl in one place. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 8 +++++--- + trace-events | 6 ++++-- + 2 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 9f06f5e..360f4f6 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -141,6 +141,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); + + void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) + { ++ trace_qxl_set_guest_bug(qxl->id); + qxl_send_events(qxl, QXL_INTERRUPT_ERROR); + qxl->guest_bug = 1; + if (qxl->guestdebug) { +@@ -1408,7 +1409,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + break; + } + trace_qxl_io_unexpected_vga_mode(d->id, +- io_port, io_port_to_string(io_port)); ++ addr, val, io_port_to_string(io_port)); + /* be nice to buggy guest drivers */ + if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && + io_port < QXL_IO_RANGE_SIZE) { +@@ -1607,9 +1608,9 @@ cancel_async: + static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, + unsigned size) + { +- PCIQXLDevice *d = opaque; ++ PCIQXLDevice *qxl = opaque; + +- trace_qxl_io_read_unexpected(d->id); ++ trace_qxl_io_read_unexpected(qxl->id); + return 0xff; + } + +@@ -1639,6 +1640,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) + uint32_t old_pending; + uint32_t le_events = cpu_to_le32(events); + ++ trace_qxl_send_events(d->id, events); + assert(qemu_spice_display_is_running(&d->ssd)); + old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); + if ((old_pending & le_events) == le_events) { +diff --git a/trace-events b/trace-events +index 8fcbc50..42dfb93 100644 +--- a/trace-events ++++ b/trace-events +@@ -925,7 +925,7 @@ qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" + qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" + qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" + qxl_io_read_unexpected(int qid) "%d" +-qxl_io_unexpected_vga_mode(int qid, uint32_t io_port, const char *desc) "%d 0x%x (%s)" ++qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" + qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" + qxl_memslot_add_guest(int qid, uint32_t slot_id, uint64_t guest_start, uint64_t guest_end) "%d %u: guest phys 0x%"PRIx64 " - 0x%" PRIx64 + qxl_post_load(int qid, const char *mode) "%d %s" +@@ -956,7 +956,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" + qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" + qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" + qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" +-qxl_spice_monitors_config(int id) "%d" ++qxl_spice_monitors_config(int qid) "%d" + qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" + qxl_spice_oom(int qid) "%d" + qxl_spice_reset_cursor(int qid) "%d" +@@ -965,6 +965,8 @@ qxl_spice_reset_memslots(int qid) "%d" + qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" + qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" + qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" ++qxl_send_events(int qid, uint32_t events) "%d %d" ++qxl_set_guest_bug(int qid) "%d" + + # hw/qxl-render.c + qxl_render_blit_guest_primary_initialized(void) "" +-- +1.7.12 + diff --git a/0223-qxl-add-trace-event-for-QXL_IO_LOG.patch b/0223-qxl-add-trace-event-for-QXL_IO_LOG.patch new file mode 100644 index 0000000..84982fa --- /dev/null +++ b/0223-qxl-add-trace-event-for-QXL_IO_LOG.patch @@ -0,0 +1,39 @@ +From f4cebc3d7a15ecccf61809c35242427e2c2e6713 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 12 Sep 2012 16:13:27 +0300 +Subject: [PATCH 223/293] qxl: add trace-event for QXL_IO_LOG + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 1 + + trace-events | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 360f4f6..1ef117a 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1515,6 +1515,7 @@ async_common: + qxl_set_mode(d, val, 0); + break; + case QXL_IO_LOG: ++ trace_qxl_io_log(d->id, d->ram->log_buf); + if (d->guestdebug) { + fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, + qemu_get_clock_ns(vm_clock), d->ram->log_buf); +diff --git a/trace-events b/trace-events +index 42dfb93..0ce69d6 100644 +--- a/trace-events ++++ b/trace-events +@@ -924,6 +924,7 @@ qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d + qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" + qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" + qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" ++qxl_io_log(int qid, const uint8_t *str) "%d %s" + qxl_io_read_unexpected(int qid) "%d" + qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" + qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" +-- +1.7.12 + diff --git a/0224-hw-qxl-support-client-monitor-configuration-via-devi.patch b/0224-hw-qxl-support-client-monitor-configuration-via-devi.patch new file mode 100644 index 0000000..56cd1e1 --- /dev/null +++ b/0224-hw-qxl-support-client-monitor-configuration-via-devi.patch @@ -0,0 +1,182 @@ +From 3ad6b56cb328a01150fc9a61ee7f4300af2a0912 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 12 Sep 2012 16:13:28 +0300 +Subject: [PATCH 224/293] hw/qxl: support client monitor configuration via + device + +Until now we used only the agent to change the monitor count and each +monitor resolution. This patch introduces the qemu part of using the +device as the mediator instead of the agent via virtio-serial. + +Spice (>=0.11.5) calls the new QXLInterface::client_monitors_config, +which returns wether the interrupt is enabled, and if so and given a non +NULL monitors config will +generate an interrupt QXL_INTERRUPT_CLIENT_MONITORS_CONFIG with crc +checksum for the guest to verify a second call hasn't interfered. + +The maximal number of monitors is limited on the QXLRom to 64. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + configure | 7 ++++++ + hw/qxl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + trace-events | 6 ++++- + 3 files changed, 91 insertions(+), 1 deletion(-) + +diff --git a/configure b/configure +index 0bfef84..ebe8b1c 100755 +--- a/configure ++++ b/configure +@@ -2716,6 +2716,9 @@ EOF + if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then + spice_qxl_io_monitors_config_async="yes" + fi ++ if $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1; then ++ spice_qxl_client_monitors_config="yes" ++ fi + else + if test "$spice" = "yes" ; then + feature_not_found "spice" +@@ -3457,6 +3460,10 @@ if test "$spice_qxl_io_monitors_config_async" = "yes" ; then + echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak + fi + ++if test "$spice_qxl_client_monitors_config" = "yes" ; then ++ echo "CONFIG_QXL_CLIENT_MONITORS_CONFIG=y" >> $config_host_mak ++fi ++ + if test "$smartcard" = "yes" ; then + echo "CONFIG_SMARTCARD=y" >> $config_host_mak + fi +diff --git a/hw/qxl.c b/hw/qxl.c +index 1ef117a..0695872 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -18,6 +18,8 @@ + * along with this program; if not, see . + */ + ++#include ++ + #include "qemu-common.h" + #include "qemu-timer.h" + #include "qemu-queue.h" +@@ -971,6 +973,79 @@ static void interface_set_client_capabilities(QXLInstance *sin, + + #endif + ++#if defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) \ ++ && SPICE_SERVER_VERSION >= 0x000b05 ++ ++static uint32_t qxl_crc32(const uint8_t *p, unsigned len) ++{ ++ /* ++ * zlib xors the seed with 0xffffffff, and xors the result ++ * again with 0xffffffff; Both are not done with linux's crc32, ++ * which we want to be compatible with, so undo that. ++ */ ++ return crc32(0xffffffff, p, len) ^ 0xffffffff; ++} ++ ++/* called from main context only */ ++static int interface_client_monitors_config(QXLInstance *sin, ++ VDAgentMonitorsConfig *monitors_config) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar); ++ int i; ++ ++ /* ++ * Older windows drivers set int_mask to 0 when their ISR is called, ++ * then later set it to ~0. So it doesn't relate to the actual interrupts ++ * handled. However, they are old, so clearly they don't support this ++ * interrupt ++ */ ++ if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 || ++ !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) { ++ trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id, ++ qxl->ram->int_mask, ++ monitors_config); ++ return 0; ++ } ++ if (!monitors_config) { ++ return 1; ++ } ++ memset(&rom->client_monitors_config, 0, ++ sizeof(rom->client_monitors_config)); ++ rom->client_monitors_config.count = monitors_config->num_of_monitors; ++ /* monitors_config->flags ignored */ ++ if (rom->client_monitors_config.count >= ++ ARRAY_SIZE(rom->client_monitors_config.heads)) { ++ trace_qxl_client_monitors_config_capped(qxl->id, ++ monitors_config->num_of_monitors, ++ ARRAY_SIZE(rom->client_monitors_config.heads)); ++ rom->client_monitors_config.count = ++ ARRAY_SIZE(rom->client_monitors_config.heads); ++ } ++ for (i = 0 ; i < rom->client_monitors_config.count ; ++i) { ++ VDAgentMonConfig *monitor = &monitors_config->monitors[i]; ++ QXLURect *rect = &rom->client_monitors_config.heads[i]; ++ /* monitor->depth ignored */ ++ rect->left = monitor->x; ++ rect->top = monitor->y; ++ rect->right = monitor->x + monitor->width; ++ rect->bottom = monitor->y + monitor->height; ++ } ++ rom->client_monitors_config_crc = qxl_crc32( ++ (const uint8_t *)&rom->client_monitors_config, ++ sizeof(rom->client_monitors_config)); ++ trace_qxl_client_monitors_config_crc(qxl->id, ++ sizeof(rom->client_monitors_config), ++ rom->client_monitors_config_crc); ++ ++ trace_qxl_interrupt_client_monitors_config(qxl->id, ++ rom->client_monitors_config.count, ++ rom->client_monitors_config.heads); ++ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG); ++ return 1; ++} ++#endif ++ + static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", +@@ -995,6 +1070,10 @@ static const QXLInterface qxl_interface = { + #if SPICE_SERVER_VERSION >= 0x000b04 + .set_client_capabilities = interface_set_client_capabilities, + #endif ++#if SPICE_SERVER_VERSION >= 0x000b05 && \ ++ defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) ++ .client_monitors_config = interface_client_monitors_config, ++#endif + }; + + static void qxl_enter_vga_mode(PCIQXLDevice *d) +diff --git a/trace-events b/trace-events +index 0ce69d6..1b19988 100644 +--- a/trace-events ++++ b/trace-events +@@ -924,7 +924,7 @@ qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d + qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" + qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" + qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" +-qxl_io_log(int qid, const uint8_t *str) "%d %s" ++qxl_io_log(int qid, const uint8_t *log_buf) "%d %s" + qxl_io_read_unexpected(int qid) "%d" + qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" + qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" +@@ -968,6 +968,10 @@ qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dir + qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" + qxl_send_events(int qid, uint32_t events) "%d %d" + qxl_set_guest_bug(int qid) "%d" ++qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p" ++qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p" ++qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d" ++qxl_client_monitors_config_crc(int qid, unsigned size, uint32_t crc32) "%d %u %u" + + # hw/qxl-render.c + qxl_render_blit_guest_primary_initialized(void) "" +-- +1.7.12 + diff --git a/0332-xhci-drop-buffering.patch b/0332-xhci-drop-buffering.patch index 1097664..67de840 100644 --- a/0332-xhci-drop-buffering.patch +++ b/0332-xhci-drop-buffering.patch @@ -1,7 +1,7 @@ -From ad14386b3f1ccd445afd30d30a343cb9fcf6c0a7 Mon Sep 17 00:00:00 2001 +From ba184fe5a0e63bd40956b456d85a01da13d6183d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 17 Aug 2012 11:04:36 +0200 -Subject: [PATCH 332/366] xhci: drop buffering +Subject: [PATCH 332/369] xhci: drop buffering This patch splits the xhci_xfer_data function into three. The xhci_xfer_data function used to do does two things: @@ -21,14 +21,16 @@ The patch also fixes reporting of transaction errors which must be reported unconditinally, not only in case the guest asks for it using the ISP flag. +[ v2: fix warning ] + Signed-off-by: Gerd Hoffmann --- - hw/usb/hcd-xhci.c | 183 +++++++++++++++++++++--------------------------------- + hw/usb/hcd-xhci.c | 185 +++++++++++++++++++++--------------------------------- trace-events | 2 +- - 2 files changed, 72 insertions(+), 113 deletions(-) + 2 files changed, 72 insertions(+), 115 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index c0a2476..c858b6d 100644 +index c0a2476..446d692 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -305,6 +305,7 @@ typedef struct XHCIState XHCIState; @@ -266,7 +268,15 @@ index c0a2476..c858b6d 100644 xhci_stall_ep(xfer); break; default: -@@ -1279,8 +1280,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) +@@ -1271,7 +1272,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + { + XHCITRB *trb_setup, *trb_status; + uint8_t bmRequestType; +- uint16_t wLength; + XHCIPort *port; + USBDevice *dev; + int ret; +@@ -1279,8 +1279,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) trb_setup = &xfer->trbs[0]; trb_status = &xfer->trbs[xfer->trb_count-1]; @@ -276,10 +286,12 @@ index c0a2476..c858b6d 100644 /* at most one Event Data TRB allowed after STATUS */ if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { -@@ -1311,18 +1311,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - bmRequestType = trb_setup->parameter; - wLength = trb_setup->parameter >> 48; +@@ -1309,19 +1308,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + } + bmRequestType = trb_setup->parameter; +- wLength = trb_setup->parameter >> 48; +- - if (xfer->data && xfer->data_alloced < wLength) { - xfer->data_alloced = 0; - g_free(xfer->data); @@ -291,11 +303,10 @@ index c0a2476..c858b6d 100644 - xfer->data_alloced = wLength; - } - xfer->data_length = wLength; -- + port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); - if (!dev) { -@@ -1336,9 +1324,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) +@@ -1336,9 +1322,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) xhci_setup_packet(xfer, dev); xfer->packet.parameter = trb_setup->parameter; @@ -305,7 +316,7 @@ index c0a2476..c858b6d 100644 ret = usb_handle_packet(dev, &xfer->packet); -@@ -1359,16 +1344,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx +@@ -1359,16 +1342,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx xfer->in_xfer = epctx->type>>2; @@ -322,7 +333,7 @@ index c0a2476..c858b6d 100644 if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { xfer->pkts = 1; } else { -@@ -1402,9 +1377,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx +@@ -1402,9 +1375,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx return -1; } @@ -332,7 +343,7 @@ index c0a2476..c858b6d 100644 ret = usb_handle_packet(dev, &xfer->packet); xhci_complete_packet(xfer, ret); -@@ -1416,20 +1388,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx +@@ -1416,20 +1386,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) { diff --git a/0333-xhci-move-device-lookup-into-xhci_setup_packet.patch b/0333-xhci-move-device-lookup-into-xhci_setup_packet.patch index 3cde29a..2ac0629 100644 --- a/0333-xhci-move-device-lookup-into-xhci_setup_packet.patch +++ b/0333-xhci-move-device-lookup-into-xhci_setup_packet.patch @@ -1,7 +1,7 @@ -From 76d49f5c5abc30f33f5b9288df68d53dba9e10f0 Mon Sep 17 00:00:00 2001 +From e144accdeb05222cf671c3bad142c81c40dbacdb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 24 Aug 2012 14:21:39 +0200 -Subject: [PATCH 333/366] xhci: move device lookup into xhci_setup_packet +Subject: [PATCH 333/369] xhci: move device lookup into xhci_setup_packet Signed-off-by: Gerd Hoffmann --- @@ -9,7 +9,7 @@ Signed-off-by: Gerd Hoffmann 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index c858b6d..303e1ac 100644 +index 446d692..c108c9d 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1196,13 +1196,38 @@ static void xhci_stall_ep(XHCITransfer *xfer) @@ -53,7 +53,7 @@ index c858b6d..303e1ac 100644 usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr); xhci_xfer_map(xfer); DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", -@@ -1260,21 +1285,11 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) +@@ -1260,20 +1285,10 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) return 0; } @@ -69,15 +69,14 @@ index c858b6d..303e1ac 100644 { XHCITRB *trb_setup, *trb_status; uint8_t bmRequestType; - uint16_t wLength; - XHCIPort *port; - USBDevice *dev; int ret; trb_setup = &xfer->trbs[0]; -@@ -1311,21 +1326,15 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) +@@ -1309,21 +1324,15 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + bmRequestType = trb_setup->parameter; - wLength = trb_setup->parameter >> 48; - port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; - dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); @@ -101,7 +100,7 @@ index c858b6d..303e1ac 100644 xhci_complete_packet(xfer, ret); if (!xfer->running_async && !xfer->running_retry) { -@@ -1336,8 +1345,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) +@@ -1334,8 +1343,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) { @@ -110,7 +109,7 @@ index c858b6d..303e1ac 100644 int ret; DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); -@@ -1350,16 +1357,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx +@@ -1348,16 +1355,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx xfer->pkts = 0; } @@ -127,7 +126,7 @@ index c858b6d..303e1ac 100644 switch(epctx->type) { case ET_INTR_OUT: case ET_INTR_IN: -@@ -1377,7 +1374,10 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx +@@ -1375,7 +1372,10 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx return -1; } @@ -139,7 +138,7 @@ index c858b6d..303e1ac 100644 xhci_complete_packet(xfer, ret); if (!xfer->running_async && !xfer->running_retry) { -@@ -1420,7 +1420,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid +@@ -1418,7 +1418,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid trace_usb_xhci_xfer_retry(xfer); assert(xfer->running_retry); diff --git a/0355-ehci-switch-to-new-style-memory-ops.patch b/0355-ehci-switch-to-new-style-memory-ops.patch deleted file mode 100644 index 78e6b4f..0000000 --- a/0355-ehci-switch-to-new-style-memory-ops.patch +++ /dev/null @@ -1,367 +0,0 @@ -From 538ee859ae415782e5be3b4a07e7db655cf70aa2 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 6 Sep 2012 11:24:51 +0200 -Subject: [PATCH 355/366] ehci: switch to new-style memory ops - -Also register different memory regions for capabilities, -operational registers and port status registers. Create -separate tracepoints for operational regs and port status -regs. Ditch a bunch of sanity checks because the memory -core will do this for us now. - -Offloading the byte, word and dword access handling to the -memory core also has the side effect of fixing ehci register -access on bigendian hosts. - -Cc: David Gibson -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 173 ++++++++++++++++++++++++++---------------------------- - trace-events | 9 ++- - 2 files changed, 90 insertions(+), 92 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 2f3e9c0..f5ba8e1 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -389,6 +389,9 @@ struct EHCIState { - USBBus bus; - qemu_irq irq; - MemoryRegion mem; -+ MemoryRegion mem_caps; -+ MemoryRegion mem_opreg; -+ MemoryRegion mem_ports; - int companion_count; - - /* properties */ -@@ -398,10 +401,10 @@ struct EHCIState { - * EHCI spec version 1.0 Section 2.3 - * Host Controller Operational Registers - */ -+ uint8_t caps[OPREGBASE]; - union { -- uint8_t mmio[MMIO_SIZE]; -+ uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)]; - struct { -- uint8_t cap[OPREGBASE]; - uint32_t usbcmd; - uint32_t usbsts; - uint32_t usbintr; -@@ -411,9 +414,9 @@ struct EHCIState { - uint32_t asynclistaddr; - uint32_t notused[9]; - uint32_t configflag; -- uint32_t portsc[NB_PORTS]; - }; - }; -+ uint32_t portsc[NB_PORTS]; - - /* - * Internal states, shadow registers, etc -@@ -471,22 +474,12 @@ static const char *ehci_state_names[] = { - }; - - static const char *ehci_mmio_names[] = { -- [CAPLENGTH] = "CAPLENGTH", -- [HCIVERSION] = "HCIVERSION", -- [HCSPARAMS] = "HCSPARAMS", -- [HCCPARAMS] = "HCCPARAMS", - [USBCMD] = "USBCMD", - [USBSTS] = "USBSTS", - [USBINTR] = "USBINTR", - [FRINDEX] = "FRINDEX", - [PERIODICLISTBASE] = "P-LIST BASE", - [ASYNCLISTADDR] = "A-LIST ADDR", -- [PORTSC_BEGIN] = "PORTSC #0", -- [PORTSC_BEGIN + 4] = "PORTSC #1", -- [PORTSC_BEGIN + 8] = "PORTSC #2", -- [PORTSC_BEGIN + 12] = "PORTSC #3", -- [PORTSC_BEGIN + 16] = "PORTSC #4", -- [PORTSC_BEGIN + 20] = "PORTSC #5", - [CONFIGFLAG] = "CONFIGFLAG", - }; - -@@ -509,7 +502,8 @@ static const char *state2str(uint32_t state) - - static const char *addr2str(target_phys_addr_t addr) - { -- return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr); -+ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), -+ addr + OPREGBASE); - } - - static void ehci_trace_usbsts(uint32_t mask, int state) -@@ -1018,7 +1012,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], - } - - s->companion_count++; -- s->mmio[0x05] = (s->companion_count << 4) | portcount; -+ s->caps[0x05] = (s->companion_count << 4) | portcount; - - return 0; - } -@@ -1063,7 +1057,8 @@ static void ehci_reset(void *opaque) - } - } - -- memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE); -+ memset(&s->opreg, 0x00, sizeof(s->opreg)); -+ memset(&s->portsc, 0x00, sizeof(s->portsc)); - - s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH; - s->usbsts = USBSTS_HALT; -@@ -1090,50 +1085,35 @@ static void ehci_reset(void *opaque) - qemu_bh_cancel(s->async_bh); - } - --static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) -+static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr, -+ unsigned size) - { - EHCIState *s = ptr; -- uint32_t val; -- -- val = s->mmio[addr]; -- -- return val; -+ return s->caps[addr]; - } - --static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr) -+static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr, -+ unsigned size) - { - EHCIState *s = ptr; - uint32_t val; - -- val = s->mmio[addr] | (s->mmio[addr+1] << 8); -- -+ val = s->opreg[addr >> 2]; -+ trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val); - return val; - } - --static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr) -+static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr, -+ unsigned size) - { - EHCIState *s = ptr; - uint32_t val; - -- val = s->mmio[addr] | (s->mmio[addr+1] << 8) | -- (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24); -- -- trace_usb_ehci_mmio_readl(addr, addr2str(addr), val); -+ val = s->portsc[addr >> 2]; -+ trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val); - return val; - } - --static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val) --{ -- fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n"); -- exit(1); --} -- --static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) --{ -- fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n"); -- exit(1); --} -- - static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) - { - USBDevice *dev = s->ports[port].dev; -@@ -1162,11 +1142,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) - } - } - --static void handle_port_status_write(EHCIState *s, int port, uint32_t val) -+static void ehci_port_write(void *ptr, target_phys_addr_t addr, -+ uint64_t val, unsigned size) - { -+ EHCIState *s = ptr; -+ int port = addr >> 2; - uint32_t *portsc = &s->portsc[port]; -+ uint32_t old = *portsc; - USBDevice *dev = s->ports[port].dev; - -+ trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val); -+ - /* Clear rwc bits */ - *portsc &= ~(val & PORTSC_RWC_MASK); - /* The guest may clear, but not set the PED bit */ -@@ -1198,39 +1184,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) - - *portsc &= ~PORTSC_RO_MASK; - *portsc |= val; -+ trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old); - } - --static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) -+static void ehci_opreg_write(void *ptr, target_phys_addr_t addr, -+ uint64_t val, unsigned size) - { - EHCIState *s = ptr; -- uint32_t *mmio = (uint32_t *)(&s->mmio[addr]); -+ uint32_t *mmio = s->opreg + (addr >> 2); - uint32_t old = *mmio; - int i; - -- trace_usb_ehci_mmio_writel(addr, addr2str(addr), val); -- -- /* Only aligned reads are allowed on OHCI */ -- if (addr & 3) { -- fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x" -- TARGET_FMT_plx "\n", addr); -- return; -- } -- -- if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) { -- handle_port_status_write(s, (addr-PORTSC)/4, val); -- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); -- return; -- } -- -- if (addr < OPREGBASE) { -- fprintf(stderr, "usb-ehci: write attempt to read-only register" -- TARGET_FMT_plx "\n", addr); -- return; -- } -- -+ trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val); - -- /* Do any register specific pre-write processing here. */ -- switch(addr) { -+ switch (addr + OPREGBASE) { - case USBCMD: - if (val & USBCMD_HCRESET) { - ehci_reset(s); -@@ -1241,7 +1208,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - /* not supporting dynamic frame list size at the moment */ - if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) { - fprintf(stderr, "attempt to set frame list size -- value %d\n", -- val & USBCMD_FLS); -+ (int)val & USBCMD_FLS); - val &= ~USBCMD_FLS; - } - -@@ -1308,7 +1275,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - } - - *mmio = val; -- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); -+ trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old); - } - - -@@ -2520,11 +2487,28 @@ static void ehci_async_bh(void *opaque) - ehci_advance_async_state(ehci); - } - --static const MemoryRegionOps ehci_mem_ops = { -- .old_mmio = { -- .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl }, -- .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel }, -- }, -+static const MemoryRegionOps ehci_mmio_caps_ops = { -+ .read = ehci_caps_read, -+ .valid.min_access_size = 1, -+ .valid.max_access_size = 4, -+ .impl.min_access_size = 1, -+ .impl.max_access_size = 1, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static const MemoryRegionOps ehci_mmio_opreg_ops = { -+ .read = ehci_opreg_read, -+ .write = ehci_opreg_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static const MemoryRegionOps ehci_mmio_port_ops = { -+ .read = ehci_port_read, -+ .write = ehci_port_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, - }; - -@@ -2681,19 +2665,19 @@ static int usb_ehci_initfn(PCIDevice *dev) - pci_conf[0x6e] = 0x00; - pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS - -- // 2.2 host controller interface version -- s->mmio[0x00] = (uint8_t) OPREGBASE; -- s->mmio[0x01] = 0x00; -- s->mmio[0x02] = 0x00; -- s->mmio[0x03] = 0x01; // HC version -- s->mmio[0x04] = NB_PORTS; // Number of downstream ports -- s->mmio[0x05] = 0x00; // No companion ports at present -- s->mmio[0x06] = 0x00; -- s->mmio[0x07] = 0x00; -- s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable -- s->mmio[0x09] = 0x68; // EECP -- s->mmio[0x0a] = 0x00; -- s->mmio[0x0b] = 0x00; -+ /* 2.2 host controller interface version */ -+ s->caps[0x00] = (uint8_t) OPREGBASE; -+ s->caps[0x01] = 0x00; -+ s->caps[0x02] = 0x00; -+ s->caps[0x03] = 0x01; /* HC version */ -+ s->caps[0x04] = NB_PORTS; /* Number of downstream ports */ -+ s->caps[0x05] = 0x00; /* No companion ports at present */ -+ s->caps[0x06] = 0x00; -+ s->caps[0x07] = 0x00; -+ s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */ -+ s->caps[0x09] = 0x68; /* EECP */ -+ s->caps[0x0a] = 0x00; -+ s->caps[0x0b] = 0x00; - - s->irq = s->dev.irq[3]; - -@@ -2712,7 +2696,18 @@ static int usb_ehci_initfn(PCIDevice *dev) - - qemu_register_reset(ehci_reset, s); - -- memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE); -+ memory_region_init(&s->mem, "ehci", MMIO_SIZE); -+ memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, -+ "capabilities", OPREGBASE); -+ memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s, -+ "operational", PORTSC_BEGIN - OPREGBASE); -+ memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s, -+ "ports", PORTSC_END - PORTSC_BEGIN); -+ -+ memory_region_add_subregion(&s->mem, 0, &s->mem_caps); -+ memory_region_add_subregion(&s->mem, OPREGBASE, &s->mem_opreg); -+ memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports); -+ - pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); - - return 0; -diff --git a/trace-events b/trace-events -index b25ae1c..a58b0b7 100644 ---- a/trace-events -+++ b/trace-events -@@ -243,9 +243,12 @@ usb_port_release(int bus, const char *port) "bus %d, port %s" - - # hw/usb/hcd-ehci.c - usb_ehci_reset(void) "=== RESET ===" --usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x" --usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x" --usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)" -+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)" -+usb_ehci_portsc_read(uint32_t addr, uint32_t port, uint32_t val) "rd mmio %04x [port %d] = %x" -+usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio %04x [port %d] = %x" -+usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio %04x [port %d] = %x (old: %x)" - usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d" - usb_ehci_state(const char *schedule, const char *state) "%s schedule %s" - usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x" --- -1.7.12 - diff --git a/0355-usb-host-allow-emulated-non-async-control-requests-w.patch b/0355-usb-host-allow-emulated-non-async-control-requests-w.patch new file mode 100644 index 0000000..752582f --- /dev/null +++ b/0355-usb-host-allow-emulated-non-async-control-requests-w.patch @@ -0,0 +1,37 @@ +From 487e24442148aa659a53f69db394642a7d93c3c6 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 6 Sep 2012 12:03:41 +0200 +Subject: [PATCH 357/366] usb-host: allow emulated (non-async) control + requests without USBPacket + +xhci needs this for USB_REQ_SET_ADDRESS due to the way +usb addressing is handled by the xhci hardware. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/host-linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c +index 8df9207..44f1a64 100644 +--- a/hw/usb/host-linux.c ++++ b/hw/usb/host-linux.c +@@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, + + /* Note request is (bRequestType << 8) | bRequest */ + trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); +- assert(p->result == 0); + + switch (request) { + case DeviceOutRequest | USB_REQ_SET_ADDRESS: +@@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, + } + + /* The rest are asynchronous */ ++ assert(p && p->result == 0); + + if (length > sizeof(dev->data_buf)) { + fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", +-- +1.7.12 + diff --git a/0356-ehci-switch-to-new-style-memory-ops.patch b/0356-ehci-switch-to-new-style-memory-ops.patch new file mode 100644 index 0000000..78e6b4f --- /dev/null +++ b/0356-ehci-switch-to-new-style-memory-ops.patch @@ -0,0 +1,367 @@ +From 538ee859ae415782e5be3b4a07e7db655cf70aa2 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 6 Sep 2012 11:24:51 +0200 +Subject: [PATCH 355/366] ehci: switch to new-style memory ops + +Also register different memory regions for capabilities, +operational registers and port status registers. Create +separate tracepoints for operational regs and port status +regs. Ditch a bunch of sanity checks because the memory +core will do this for us now. + +Offloading the byte, word and dword access handling to the +memory core also has the side effect of fixing ehci register +access on bigendian hosts. + +Cc: David Gibson +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-ehci.c | 173 ++++++++++++++++++++++++++---------------------------- + trace-events | 9 ++- + 2 files changed, 90 insertions(+), 92 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 2f3e9c0..f5ba8e1 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -389,6 +389,9 @@ struct EHCIState { + USBBus bus; + qemu_irq irq; + MemoryRegion mem; ++ MemoryRegion mem_caps; ++ MemoryRegion mem_opreg; ++ MemoryRegion mem_ports; + int companion_count; + + /* properties */ +@@ -398,10 +401,10 @@ struct EHCIState { + * EHCI spec version 1.0 Section 2.3 + * Host Controller Operational Registers + */ ++ uint8_t caps[OPREGBASE]; + union { +- uint8_t mmio[MMIO_SIZE]; ++ uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)]; + struct { +- uint8_t cap[OPREGBASE]; + uint32_t usbcmd; + uint32_t usbsts; + uint32_t usbintr; +@@ -411,9 +414,9 @@ struct EHCIState { + uint32_t asynclistaddr; + uint32_t notused[9]; + uint32_t configflag; +- uint32_t portsc[NB_PORTS]; + }; + }; ++ uint32_t portsc[NB_PORTS]; + + /* + * Internal states, shadow registers, etc +@@ -471,22 +474,12 @@ static const char *ehci_state_names[] = { + }; + + static const char *ehci_mmio_names[] = { +- [CAPLENGTH] = "CAPLENGTH", +- [HCIVERSION] = "HCIVERSION", +- [HCSPARAMS] = "HCSPARAMS", +- [HCCPARAMS] = "HCCPARAMS", + [USBCMD] = "USBCMD", + [USBSTS] = "USBSTS", + [USBINTR] = "USBINTR", + [FRINDEX] = "FRINDEX", + [PERIODICLISTBASE] = "P-LIST BASE", + [ASYNCLISTADDR] = "A-LIST ADDR", +- [PORTSC_BEGIN] = "PORTSC #0", +- [PORTSC_BEGIN + 4] = "PORTSC #1", +- [PORTSC_BEGIN + 8] = "PORTSC #2", +- [PORTSC_BEGIN + 12] = "PORTSC #3", +- [PORTSC_BEGIN + 16] = "PORTSC #4", +- [PORTSC_BEGIN + 20] = "PORTSC #5", + [CONFIGFLAG] = "CONFIGFLAG", + }; + +@@ -509,7 +502,8 @@ static const char *state2str(uint32_t state) + + static const char *addr2str(target_phys_addr_t addr) + { +- return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr); ++ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), ++ addr + OPREGBASE); + } + + static void ehci_trace_usbsts(uint32_t mask, int state) +@@ -1018,7 +1012,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], + } + + s->companion_count++; +- s->mmio[0x05] = (s->companion_count << 4) | portcount; ++ s->caps[0x05] = (s->companion_count << 4) | portcount; + + return 0; + } +@@ -1063,7 +1057,8 @@ static void ehci_reset(void *opaque) + } + } + +- memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE); ++ memset(&s->opreg, 0x00, sizeof(s->opreg)); ++ memset(&s->portsc, 0x00, sizeof(s->portsc)); + + s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH; + s->usbsts = USBSTS_HALT; +@@ -1090,50 +1085,35 @@ static void ehci_reset(void *opaque) + qemu_bh_cancel(s->async_bh); + } + +-static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) ++static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr, ++ unsigned size) + { + EHCIState *s = ptr; +- uint32_t val; +- +- val = s->mmio[addr]; +- +- return val; ++ return s->caps[addr]; + } + +-static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr) ++static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr, ++ unsigned size) + { + EHCIState *s = ptr; + uint32_t val; + +- val = s->mmio[addr] | (s->mmio[addr+1] << 8); +- ++ val = s->opreg[addr >> 2]; ++ trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val); + return val; + } + +-static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr) ++static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr, ++ unsigned size) + { + EHCIState *s = ptr; + uint32_t val; + +- val = s->mmio[addr] | (s->mmio[addr+1] << 8) | +- (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24); +- +- trace_usb_ehci_mmio_readl(addr, addr2str(addr), val); ++ val = s->portsc[addr >> 2]; ++ trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val); + return val; + } + +-static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val) +-{ +- fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n"); +- exit(1); +-} +- +-static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) +-{ +- fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n"); +- exit(1); +-} +- + static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) + { + USBDevice *dev = s->ports[port].dev; +@@ -1162,11 +1142,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) + } + } + +-static void handle_port_status_write(EHCIState *s, int port, uint32_t val) ++static void ehci_port_write(void *ptr, target_phys_addr_t addr, ++ uint64_t val, unsigned size) + { ++ EHCIState *s = ptr; ++ int port = addr >> 2; + uint32_t *portsc = &s->portsc[port]; ++ uint32_t old = *portsc; + USBDevice *dev = s->ports[port].dev; + ++ trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val); ++ + /* Clear rwc bits */ + *portsc &= ~(val & PORTSC_RWC_MASK); + /* The guest may clear, but not set the PED bit */ +@@ -1198,39 +1184,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) + + *portsc &= ~PORTSC_RO_MASK; + *portsc |= val; ++ trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old); + } + +-static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) ++static void ehci_opreg_write(void *ptr, target_phys_addr_t addr, ++ uint64_t val, unsigned size) + { + EHCIState *s = ptr; +- uint32_t *mmio = (uint32_t *)(&s->mmio[addr]); ++ uint32_t *mmio = s->opreg + (addr >> 2); + uint32_t old = *mmio; + int i; + +- trace_usb_ehci_mmio_writel(addr, addr2str(addr), val); +- +- /* Only aligned reads are allowed on OHCI */ +- if (addr & 3) { +- fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x" +- TARGET_FMT_plx "\n", addr); +- return; +- } +- +- if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) { +- handle_port_status_write(s, (addr-PORTSC)/4, val); +- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); +- return; +- } +- +- if (addr < OPREGBASE) { +- fprintf(stderr, "usb-ehci: write attempt to read-only register" +- TARGET_FMT_plx "\n", addr); +- return; +- } +- ++ trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val); + +- /* Do any register specific pre-write processing here. */ +- switch(addr) { ++ switch (addr + OPREGBASE) { + case USBCMD: + if (val & USBCMD_HCRESET) { + ehci_reset(s); +@@ -1241,7 +1208,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + /* not supporting dynamic frame list size at the moment */ + if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) { + fprintf(stderr, "attempt to set frame list size -- value %d\n", +- val & USBCMD_FLS); ++ (int)val & USBCMD_FLS); + val &= ~USBCMD_FLS; + } + +@@ -1308,7 +1275,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + } + + *mmio = val; +- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); ++ trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old); + } + + +@@ -2520,11 +2487,28 @@ static void ehci_async_bh(void *opaque) + ehci_advance_async_state(ehci); + } + +-static const MemoryRegionOps ehci_mem_ops = { +- .old_mmio = { +- .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl }, +- .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel }, +- }, ++static const MemoryRegionOps ehci_mmio_caps_ops = { ++ .read = ehci_caps_read, ++ .valid.min_access_size = 1, ++ .valid.max_access_size = 4, ++ .impl.min_access_size = 1, ++ .impl.max_access_size = 1, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static const MemoryRegionOps ehci_mmio_opreg_ops = { ++ .read = ehci_opreg_read, ++ .write = ehci_opreg_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static const MemoryRegionOps ehci_mmio_port_ops = { ++ .read = ehci_port_read, ++ .write = ehci_port_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +@@ -2681,19 +2665,19 @@ static int usb_ehci_initfn(PCIDevice *dev) + pci_conf[0x6e] = 0x00; + pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS + +- // 2.2 host controller interface version +- s->mmio[0x00] = (uint8_t) OPREGBASE; +- s->mmio[0x01] = 0x00; +- s->mmio[0x02] = 0x00; +- s->mmio[0x03] = 0x01; // HC version +- s->mmio[0x04] = NB_PORTS; // Number of downstream ports +- s->mmio[0x05] = 0x00; // No companion ports at present +- s->mmio[0x06] = 0x00; +- s->mmio[0x07] = 0x00; +- s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable +- s->mmio[0x09] = 0x68; // EECP +- s->mmio[0x0a] = 0x00; +- s->mmio[0x0b] = 0x00; ++ /* 2.2 host controller interface version */ ++ s->caps[0x00] = (uint8_t) OPREGBASE; ++ s->caps[0x01] = 0x00; ++ s->caps[0x02] = 0x00; ++ s->caps[0x03] = 0x01; /* HC version */ ++ s->caps[0x04] = NB_PORTS; /* Number of downstream ports */ ++ s->caps[0x05] = 0x00; /* No companion ports at present */ ++ s->caps[0x06] = 0x00; ++ s->caps[0x07] = 0x00; ++ s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */ ++ s->caps[0x09] = 0x68; /* EECP */ ++ s->caps[0x0a] = 0x00; ++ s->caps[0x0b] = 0x00; + + s->irq = s->dev.irq[3]; + +@@ -2712,7 +2696,18 @@ static int usb_ehci_initfn(PCIDevice *dev) + + qemu_register_reset(ehci_reset, s); + +- memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE); ++ memory_region_init(&s->mem, "ehci", MMIO_SIZE); ++ memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, ++ "capabilities", OPREGBASE); ++ memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s, ++ "operational", PORTSC_BEGIN - OPREGBASE); ++ memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s, ++ "ports", PORTSC_END - PORTSC_BEGIN); ++ ++ memory_region_add_subregion(&s->mem, 0, &s->mem_caps); ++ memory_region_add_subregion(&s->mem, OPREGBASE, &s->mem_opreg); ++ memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports); ++ + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); + + return 0; +diff --git a/trace-events b/trace-events +index b25ae1c..a58b0b7 100644 +--- a/trace-events ++++ b/trace-events +@@ -243,9 +243,12 @@ usb_port_release(int bus, const char *port) "bus %d, port %s" + + # hw/usb/hcd-ehci.c + usb_ehci_reset(void) "=== RESET ===" +-usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x" +-usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x" +-usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)" ++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)" ++usb_ehci_portsc_read(uint32_t addr, uint32_t port, uint32_t val) "rd mmio %04x [port %d] = %x" ++usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio %04x [port %d] = %x" ++usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio %04x [port %d] = %x (old: %x)" + usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d" + usb_ehci_state(const char *schedule, const char *state) "%s schedule %s" + usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x" +-- +1.7.12 + diff --git a/0356-xhci-drop-unused-wlength.patch b/0356-xhci-drop-unused-wlength.patch deleted file mode 100644 index 7bc3008..0000000 --- a/0356-xhci-drop-unused-wlength.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0b32fd99ab948db3b4cac32562272095a2594f4c Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 6 Sep 2012 11:55:06 +0200 -Subject: [PATCH 356/366] xhci: drop unused wlength - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 2918e64..e0ca690 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -1505,7 +1505,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - { - XHCITRB *trb_setup, *trb_status; - uint8_t bmRequestType; -- uint16_t wLength; - int ret; - - trb_setup = &xfer->trbs[0]; -@@ -1540,7 +1539,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - } - - bmRequestType = trb_setup->parameter; -- wLength = trb_setup->parameter >> 48; - - xfer->in_xfer = bmRequestType & USB_DIR_IN; - xfer->iso_xfer = false; --- -1.7.12 - diff --git a/0357-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch b/0357-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch new file mode 100644 index 0000000..803ab11 --- /dev/null +++ b/0357-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch @@ -0,0 +1,34 @@ +From 2ebb3309738501fcc9e8da807866fa4225bb5e91 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 10 Sep 2012 11:44:08 +0200 +Subject: [PATCH 357/369] ehci: Fix interrupts stopping when Interrupt + Threshold Control is 8 + +If Interrupt Threshold Control is 8 or a multiple of 8, then +s->usbsts_frindex can become exactly 0x4000, at which point +(s->usbsts_frindex > s->frindex) will never become true, as +s->usbsts_frindex will not be lowered / reset in this case. + +This patch fixes this. + +Signed-off-by: Hans de Goede +--- + hw/usb/hcd-ehci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index f5ba8e1..54273d7 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -2413,7 +2413,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames) + if (ehci->frindex == 0x00004000) { + ehci_raise_irq(ehci, USBSTS_FLR); + ehci->frindex = 0; +- if (ehci->usbsts_frindex > 0x00004000) { ++ if (ehci->usbsts_frindex >= 0x00004000) { + ehci->usbsts_frindex -= 0x00004000; + } else { + ehci->usbsts_frindex = 0; +-- +1.7.12 + diff --git a/0357-usb-host-allow-emulated-non-async-control-requests-w.patch b/0357-usb-host-allow-emulated-non-async-control-requests-w.patch deleted file mode 100644 index 752582f..0000000 --- a/0357-usb-host-allow-emulated-non-async-control-requests-w.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 487e24442148aa659a53f69db394642a7d93c3c6 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 6 Sep 2012 12:03:41 +0200 -Subject: [PATCH 357/366] usb-host: allow emulated (non-async) control - requests without USBPacket - -xhci needs this for USB_REQ_SET_ADDRESS due to the way -usb addressing is handled by the xhci hardware. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/host-linux.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c -index 8df9207..44f1a64 100644 ---- a/hw/usb/host-linux.c -+++ b/hw/usb/host-linux.c -@@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, - - /* Note request is (bRequestType << 8) | bRequest */ - trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); -- assert(p->result == 0); - - switch (request) { - case DeviceOutRequest | USB_REQ_SET_ADDRESS: -@@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, - } - - /* The rest are asynchronous */ -+ assert(p && p->result == 0); - - if (length > sizeof(dev->data_buf)) { - fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", --- -1.7.12 - diff --git a/0358-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch b/0358-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch new file mode 100644 index 0000000..9608c63 --- /dev/null +++ b/0358-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch @@ -0,0 +1,57 @@ +From d1034a88fdd8ad693a5cc2cb75af946e1562ff09 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 10 Sep 2012 12:38:21 +0200 +Subject: [PATCH 358/369] ehci: Don't process too much frames in 1 timer tick + (v2) + +The Linux ehci isoc scheduling code fills the entire schedule ahead of +time minus 80 frames. If we make a large jump in where we are in the +schedule, ie 40 frames, then the scheduler all of a sudden will only have +40 frames left to work in, causing it to fail packet submissions +with error -27 (-EFBIG). + +Changes in v2: +-Don't hardcode a maximum number of frames to process in one tick, instead: + -Process a minimum number of frames to ensure we do eventually catch up + -Stop (after the minimum number) when the guest has requested an irq + +Signed-off-by: Hans de Goede +--- + hw/usb/hcd-ehci.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 54273d7..6ce727c 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -139,6 +139,7 @@ + #define NB_PORTS 6 // Number of downstream ports + #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction + #define MAX_QH 100 // Max allowable queue heads in a chain ++#define MIN_FR_PER_TICK 3 // Min frames to process when catching up + + /* Internal periodic / asynchronous schedule state machine states + */ +@@ -2448,6 +2449,19 @@ static void ehci_frame_timer(void *opaque) + } + + for (i = 0; i < frames; i++) { ++ /* ++ * If we're running behind schedule, we should not catch up ++ * too fast, as that will make some guests unhappy: ++ * 1) We must process a minimum of MIN_FR_PER_TICK frames, ++ * otherwise we will never catch up ++ * 2) Process frames until the guest has requested an irq (IOC) ++ */ ++ if (i >= MIN_FR_PER_TICK) { ++ ehci_commit_irq(ehci); ++ if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) { ++ break; ++ } ++ } + ehci_update_frindex(ehci, 1); + ehci_advance_periodic_state(ehci); + ehci->last_run_ns += FRAME_TIMER_NS; +-- +1.7.12 + diff --git a/0358-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch b/0358-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch deleted file mode 100644 index f40d17b..0000000 --- a/0358-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 833eeda8129b2cf4955a34600b60c01e00652526 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 12:13:41 +0200 -Subject: [PATCH 358/366] ehci: Don't set seen to 0 when removing unseen - queue-heads - -When removing unseen queue-heads from the async queue list, we should not -set the seen flag to 0, as this may cause them to be removed by -ehci_queues_rip_unused() during the next call to ehci_advance_async_state() -if the timer is late or running at a low frequency. - -Note: -1) This *may* have caused the instant unlink / relinks described in commit - 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0 - -2) Rather then putting more if-s inside ehci_queues_rip_unused, this patch - instead introduces a new ehci_queues_rip_unseen function. - -3) This patch also makes it save to call ehci_queues_rip_unseen() multiple - times, which gets used in the folluw up patch titled: - "ehci: Walk async schedule before and after migration" - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 24 ++++++++++++++++++------ - 1 file changed, 18 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index f5ba8e1..6f48132 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -847,10 +847,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, - return NULL; - } - --static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) -+static void ehci_queues_rip_unused(EHCIState *ehci, int async) - { - EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; -- const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL; -+ const char *warn = async ? "guest unlinked busy QH" : NULL; - uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; - EHCIQueue *q, *tmp; - -@@ -860,13 +860,25 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) - q->ts = ehci->last_run_ns; - continue; - } -- if (!flush && ehci->last_run_ns < q->ts + maxage) { -+ if (ehci->last_run_ns < q->ts + maxage) { - continue; - } - ehci_free_queue(q, warn); - } - } - -+static void ehci_queues_rip_unseen(EHCIState *ehci, int async) -+{ -+ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; -+ EHCIQueue *q, *tmp; -+ -+ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { -+ if (!q->seen) { -+ ehci_free_queue(q, NULL); -+ } -+ } -+} -+ - static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) - { - EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; -@@ -1699,7 +1711,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) - ehci_set_usbsts(ehci, USBSTS_REC); - } - -- ehci_queues_rip_unused(ehci, async, 0); -+ ehci_queues_rip_unused(ehci, async); - - /* Find the head of the list (4.9.1.1) */ - for(i = 0; i < MAX_QH; i++) { -@@ -2331,7 +2343,7 @@ static void ehci_advance_async_state(EHCIState *ehci) - */ - if (ehci->usbcmd & USBCMD_IAAD) { - /* Remove all unseen qhs from the async qhs queue */ -- ehci_queues_rip_unused(ehci, async, 1); -+ ehci_queues_rip_unseen(ehci, async); - trace_usb_ehci_doorbell_ack(); - ehci->usbcmd &= ~USBCMD_IAAD; - ehci_raise_irq(ehci, USBSTS_IAA); -@@ -2384,7 +2396,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) - ehci_set_fetch_addr(ehci, async,entry); - ehci_set_state(ehci, async, EST_FETCHENTRY); - ehci_advance_state(ehci, async); -- ehci_queues_rip_unused(ehci, async, 0); -+ ehci_queues_rip_unused(ehci, async); - break; - - default: --- -1.7.12 - diff --git a/0359-configure-usbredir-fixes.patch b/0359-configure-usbredir-fixes.patch new file mode 100644 index 0000000..ff0454b --- /dev/null +++ b/0359-configure-usbredir-fixes.patch @@ -0,0 +1,33 @@ +From 31bb27a1393168657cb53deff12d4b58601e4d72 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Tue, 11 Sep 2012 18:57:58 +0000 +Subject: [PATCH 359/369] configure: usbredir fixes + +usbredir is only used by system emulation, so add the libraries to +libs_softmmu instead of LIBS. + +Cc: Michael Tokarev +Cc: Gerd Hoffmann +Signed-off-by: Aurelien Jarno +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +--- + configure | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure b/configure +index 25c406f..d63530a 100755 +--- a/configure ++++ b/configure +@@ -2770,7 +2770,7 @@ if test "$usb_redir" != "no" ; then + usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) + usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) + QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags" +- LIBS="$LIBS $usb_redir_libs" ++ libs_softmmu="$libs_softmmu $usb_redir_libs" + else + if test "$usb_redir" = "yes"; then + feature_not_found "usb-redir" +-- +1.7.12 + diff --git a/0359-ehci-Walk-async-schedule-before-and-after-migration.patch b/0359-ehci-Walk-async-schedule-before-and-after-migration.patch deleted file mode 100644 index 3c2bf54..0000000 --- a/0359-ehci-Walk-async-schedule-before-and-after-migration.patch +++ /dev/null @@ -1,66 +0,0 @@ -From fec70ddafe1632f40608ef6917760a7f946f278a Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 12:07:10 +0200 -Subject: [PATCH 359/366] ehci: Walk async schedule before and after migration - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 6f48132..30d2b56 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -34,6 +34,7 @@ - #include "monitor.h" - #include "trace.h" - #include "dma.h" -+#include "sysemu.h" - - #define EHCI_DEBUG 0 - -@@ -2558,6 +2559,32 @@ static int usb_ehci_post_load(void *opaque, int version_id) - return 0; - } - -+static void usb_ehci_vm_state_change(void *opaque, int running, RunState state) -+{ -+ EHCIState *ehci = opaque; -+ -+ /* -+ * We don't migrate the EHCIQueue-s, instead we rebuild them for the -+ * schedule in guest memory. We must do the rebuilt ASAP, so that -+ * USB-devices which have async handled packages have a packet in the -+ * ep queue to match the completion with. -+ */ -+ if (state == RUN_STATE_RUNNING) { -+ ehci_advance_async_state(ehci); -+ } -+ -+ /* -+ * The schedule rebuilt from guest memory could cause the migration dest -+ * to miss a QH unlink, and fail to cancel packets, since the unlinked QH -+ * will never have existed on the destination. Therefor we must flush the -+ * async schedule on savevm to catch any not yet noticed unlinks. -+ */ -+ if (state == RUN_STATE_SAVE_VM) { -+ ehci_advance_async_state(ehci); -+ ehci_queues_rip_unseen(ehci, 1); -+ } -+} -+ - static const VMStateDescription vmstate_ehci = { - .name = "ehci", - .version_id = 2, -@@ -2707,6 +2734,7 @@ static int usb_ehci_initfn(PCIDevice *dev) - usb_packet_init(&s->ipacket); - - qemu_register_reset(ehci_reset, s); -+ qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s); - - memory_region_init(&s->mem, "ehci", MMIO_SIZE); - memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, --- -1.7.12 - diff --git a/0360-ehci-Don-t-process-too-much-frames-in-1-timer-tick.patch b/0360-ehci-Don-t-process-too-much-frames-in-1-timer-tick.patch deleted file mode 100644 index fb0fe6b..0000000 --- a/0360-ehci-Don-t-process-too-much-frames-in-1-timer-tick.patch +++ /dev/null @@ -1,49 +0,0 @@ -From d2901e4798cb106d5b265aa4e3ae05c06bf2bd1c Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 6 Sep 2012 17:10:48 +0200 -Subject: [PATCH 360/366] ehci: Don't process too much frames in 1 timer tick - -The Linux ehci isoc scheduling code fills the entire schedule ahead of -time minus 80 frames. If we make a large jump in where we are in the -schedule, ie 40 frames, then the scheduler all of a sudden will only have -40 frames left to work in, causing it to fail packet submissions -with error -27 (-EFBIG). - -Note at first I had MAX_FR_PER_TICK set to 8, which works well with newer -Linux guest kernels, but not with older ones (such as the RHEL-6 kernel). - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 30d2b56..5398544 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -140,6 +140,7 @@ - #define NB_PORTS 6 // Number of downstream ports - #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction - #define MAX_QH 100 // Max allowable queue heads in a chain -+#define MAX_FR_PER_TICK 4 /* Max frames to process in one timer tick */ - - /* Internal periodic / asynchronous schedule state machine states - */ -@@ -2460,6 +2461,14 @@ static void ehci_frame_timer(void *opaque) - DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames); - } - -+ /* -+ * Processing too much frames at once causes the Linux EHCI isoc -+ * scheduling code to fail packet re-submissions with -EFBIG. -+ */ -+ if (frames > MAX_FR_PER_TICK) { -+ frames = MAX_FR_PER_TICK; -+ } -+ - for (i = 0; i < frames; i++) { - ehci_update_frindex(ehci, 1); - ehci_advance_periodic_state(ehci); --- -1.7.12 - diff --git a/0360-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch b/0360-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch new file mode 100644 index 0000000..f40d17b --- /dev/null +++ b/0360-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch @@ -0,0 +1,101 @@ +From 833eeda8129b2cf4955a34600b60c01e00652526 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 5 Sep 2012 12:13:41 +0200 +Subject: [PATCH 358/366] ehci: Don't set seen to 0 when removing unseen + queue-heads + +When removing unseen queue-heads from the async queue list, we should not +set the seen flag to 0, as this may cause them to be removed by +ehci_queues_rip_unused() during the next call to ehci_advance_async_state() +if the timer is late or running at a low frequency. + +Note: +1) This *may* have caused the instant unlink / relinks described in commit + 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0 + +2) Rather then putting more if-s inside ehci_queues_rip_unused, this patch + instead introduces a new ehci_queues_rip_unseen function. + +3) This patch also makes it save to call ehci_queues_rip_unseen() multiple + times, which gets used in the folluw up patch titled: + "ehci: Walk async schedule before and after migration" + +Signed-off-by: Hans de Goede +--- + hw/usb/hcd-ehci.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index f5ba8e1..6f48132 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -847,10 +847,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, + return NULL; + } + +-static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) ++static void ehci_queues_rip_unused(EHCIState *ehci, int async) + { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; +- const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL; ++ const char *warn = async ? "guest unlinked busy QH" : NULL; + uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; + EHCIQueue *q, *tmp; + +@@ -860,13 +860,25 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) + q->ts = ehci->last_run_ns; + continue; + } +- if (!flush && ehci->last_run_ns < q->ts + maxage) { ++ if (ehci->last_run_ns < q->ts + maxage) { + continue; + } + ehci_free_queue(q, warn); + } + } + ++static void ehci_queues_rip_unseen(EHCIState *ehci, int async) ++{ ++ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; ++ EHCIQueue *q, *tmp; ++ ++ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { ++ if (!q->seen) { ++ ehci_free_queue(q, NULL); ++ } ++ } ++} ++ + static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) + { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; +@@ -1699,7 +1711,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) + ehci_set_usbsts(ehci, USBSTS_REC); + } + +- ehci_queues_rip_unused(ehci, async, 0); ++ ehci_queues_rip_unused(ehci, async); + + /* Find the head of the list (4.9.1.1) */ + for(i = 0; i < MAX_QH; i++) { +@@ -2331,7 +2343,7 @@ static void ehci_advance_async_state(EHCIState *ehci) + */ + if (ehci->usbcmd & USBCMD_IAAD) { + /* Remove all unseen qhs from the async qhs queue */ +- ehci_queues_rip_unused(ehci, async, 1); ++ ehci_queues_rip_unseen(ehci, async); + trace_usb_ehci_doorbell_ack(); + ehci->usbcmd &= ~USBCMD_IAAD; + ehci_raise_irq(ehci, USBSTS_IAA); +@@ -2384,7 +2396,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) + ehci_set_fetch_addr(ehci, async,entry); + ehci_set_state(ehci, async, EST_FETCHENTRY); + ehci_advance_state(ehci, async); +- ehci_queues_rip_unused(ehci, async, 0); ++ ehci_queues_rip_unused(ehci, async); + break; + + default: +-- +1.7.12 + diff --git a/0361-ehci-Walk-async-schedule-before-and-after-migration.patch b/0361-ehci-Walk-async-schedule-before-and-after-migration.patch new file mode 100644 index 0000000..3c2bf54 --- /dev/null +++ b/0361-ehci-Walk-async-schedule-before-and-after-migration.patch @@ -0,0 +1,66 @@ +From fec70ddafe1632f40608ef6917760a7f946f278a Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 5 Sep 2012 12:07:10 +0200 +Subject: [PATCH 359/366] ehci: Walk async schedule before and after migration + +Signed-off-by: Hans de Goede +--- + hw/usb/hcd-ehci.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 6f48132..30d2b56 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -34,6 +34,7 @@ + #include "monitor.h" + #include "trace.h" + #include "dma.h" ++#include "sysemu.h" + + #define EHCI_DEBUG 0 + +@@ -2558,6 +2559,32 @@ static int usb_ehci_post_load(void *opaque, int version_id) + return 0; + } + ++static void usb_ehci_vm_state_change(void *opaque, int running, RunState state) ++{ ++ EHCIState *ehci = opaque; ++ ++ /* ++ * We don't migrate the EHCIQueue-s, instead we rebuild them for the ++ * schedule in guest memory. We must do the rebuilt ASAP, so that ++ * USB-devices which have async handled packages have a packet in the ++ * ep queue to match the completion with. ++ */ ++ if (state == RUN_STATE_RUNNING) { ++ ehci_advance_async_state(ehci); ++ } ++ ++ /* ++ * The schedule rebuilt from guest memory could cause the migration dest ++ * to miss a QH unlink, and fail to cancel packets, since the unlinked QH ++ * will never have existed on the destination. Therefor we must flush the ++ * async schedule on savevm to catch any not yet noticed unlinks. ++ */ ++ if (state == RUN_STATE_SAVE_VM) { ++ ehci_advance_async_state(ehci); ++ ehci_queues_rip_unseen(ehci, 1); ++ } ++} ++ + static const VMStateDescription vmstate_ehci = { + .name = "ehci", + .version_id = 2, +@@ -2707,6 +2734,7 @@ static int usb_ehci_initfn(PCIDevice *dev) + usb_packet_init(&s->ipacket); + + qemu_register_reset(ehci_reset, s); ++ qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s); + + memory_region_init(&s->mem, "ehci", MMIO_SIZE); + memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, +-- +1.7.12 + diff --git a/0361-usb-redir-Change-cancelled-packet-code-into-a-generi.patch b/0361-usb-redir-Change-cancelled-packet-code-into-a-generi.patch deleted file mode 100644 index 2efd733..0000000 --- a/0361-usb-redir-Change-cancelled-packet-code-into-a-generi.patch +++ /dev/null @@ -1,184 +0,0 @@ -From efbf5d06a89ec7b329d2aa15d3a6ea023b63c646 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 4 Sep 2012 14:18:34 +0200 -Subject: [PATCH 361/365] usb-redir: Change cancelled packet code into a - generic packet-id queue - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 102 +++++++++++++++++++++++++++++++++++++----------------- - 1 file changed, 71 insertions(+), 31 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 9cbcddb..08776d9 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -43,7 +43,6 @@ - #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) - #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) - --typedef struct Cancelled Cancelled; - typedef struct USBRedirDevice USBRedirDevice; - - /* Struct to hold buffered packets (iso or int input packets) */ -@@ -69,6 +68,18 @@ struct endp_data { - int bufpq_target_size; - }; - -+struct PacketIdQueueEntry { -+ uint64_t id; -+ QTAILQ_ENTRY(PacketIdQueueEntry)next; -+}; -+ -+struct PacketIdQueue { -+ USBRedirDevice *dev; -+ const char *name; -+ QTAILQ_HEAD(, PacketIdQueueEntry) head; -+ int size; -+}; -+ - struct USBRedirDevice { - USBDevice dev; - /* Properties */ -@@ -86,7 +97,7 @@ struct USBRedirDevice { - int64_t next_attach_time; - struct usbredirparser *parser; - struct endp_data endpoint[MAX_ENDPOINTS]; -- QTAILQ_HEAD(, Cancelled) cancelled; -+ struct PacketIdQueue cancelled; - /* Data for device filtering */ - struct usb_redir_device_connect_header device_info; - struct usb_redir_interface_info_header interface_info; -@@ -94,11 +105,6 @@ struct USBRedirDevice { - int filter_rules_count; - }; - --struct Cancelled { -- uint64_t id; -- QTAILQ_ENTRY(Cancelled)next; --}; -- - static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); - static void usbredir_device_connect(void *priv, - struct usb_redir_device_connect_header *device_connect); -@@ -249,37 +255,75 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - * Cancelled and buffered packets helpers - */ - --static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) -+static void packet_id_queue_init(struct PacketIdQueue *q, -+ USBRedirDevice *dev, const char *name) - { -- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -- Cancelled *c; -+ q->dev = dev; -+ q->name = name; -+ QTAILQ_INIT(&q->head); -+ q->size = 0; -+} -+ -+static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ -+ DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); -+ -+ e = g_malloc0(sizeof(struct PacketIdQueueEntry)); -+ e->id = id; -+ QTAILQ_INSERT_TAIL(&q->head, e, next); -+ q->size++; -+} -+ -+static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ -+ QTAILQ_FOREACH(e, &q->head, next) { -+ if (e->id == id) { -+ DPRINTF("removing packet id %"PRIu64" from %s queue\n", -+ id, q->name); -+ QTAILQ_REMOVE(&q->head, e, next); -+ q->size--; -+ g_free(e); -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+static void packet_id_queue_empty(struct PacketIdQueue *q) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e, *next_e; - -- DPRINTF("cancel packet id %"PRIu64"\n", p->id); -+ DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name); - -- c = g_malloc0(sizeof(Cancelled)); -- c->id = p->id; -- QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); -+ QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { -+ QTAILQ_REMOVE(&q->head, e, next); -+ g_free(e); -+ } -+ q->size = 0; -+} - -+static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) -+{ -+ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -+ -+ packet_id_queue_add(&dev->cancelled, p->id); - usbredirparser_send_cancel_data_packet(dev->parser, p->id); - usbredirparser_do_write(dev->parser); - } - - static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) - { -- Cancelled *c; -- - if (!dev->dev.attached) { - return 1; /* Treat everything as cancelled after a disconnect */ - } -- -- QTAILQ_FOREACH(c, &dev->cancelled, next) { -- if (c->id == id) { -- QTAILQ_REMOVE(&dev->cancelled, c, next); -- g_free(c); -- return 1; -- } -- } -- return 0; -+ return packet_id_queue_remove(&dev->cancelled, id); - } - - static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, -@@ -942,7 +986,7 @@ static int usbredir_initfn(USBDevice *udev) - dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - -- QTAILQ_INIT(&dev->cancelled); -+ packet_id_queue_init(&dev->cancelled, dev, "cancelled"); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -@@ -960,13 +1004,9 @@ static int usbredir_initfn(USBDevice *udev) - - static void usbredir_cleanup_device_queues(USBRedirDevice *dev) - { -- Cancelled *c, *next_c; - int i; - -- QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { -- QTAILQ_REMOVE(&dev->cancelled, c, next); -- g_free(c); -- } -+ packet_id_queue_empty(&dev->cancelled); - for (i = 0; i < MAX_ENDPOINTS; i++) { - usbredir_free_bufpq(dev, I2EP(i)); - } --- -1.7.12 - diff --git a/0362-usb-redir-Add-an-already_in_flight-packet-id-queue.patch b/0362-usb-redir-Add-an-already_in_flight-packet-id-queue.patch deleted file mode 100644 index 10c9aa3..0000000 --- a/0362-usb-redir-Add-an-already_in_flight-packet-id-queue.patch +++ /dev/null @@ -1,119 +0,0 @@ -From b422d151d0861ed346bed7cddb410a6b4c67711b Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 4 Sep 2012 17:03:54 +0200 -Subject: [PATCH 362/365] usb-redir: Add an already_in_flight packet-id queue - -After a live migration, the usb-hcd will re-queue all packets by -walking over the schedule in the guest memory again, but requests which -were encountered on the migration source before will already be in flight, -so these should *not* be re-send to the usbredir-host. - -This patch adds an already in flight packet ud queue, which will be filled by -the source before migration and then moved over to the migration dest, any -async handled packets are then checked against this queue to avoid sending -the same packet to the usbredir-host twice. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 08776d9..1c8edd3 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -98,6 +98,7 @@ struct USBRedirDevice { - struct usbredirparser *parser; - struct endp_data endpoint[MAX_ENDPOINTS]; - struct PacketIdQueue cancelled; -+ struct PacketIdQueue already_in_flight; - /* Data for device filtering */ - struct usb_redir_device_connect_header device_info; - struct usb_redir_interface_info_header interface_info; -@@ -326,6 +327,34 @@ static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) - return packet_id_queue_remove(&dev->cancelled, id); - } - -+static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, -+ struct USBEndpoint *ep) -+{ -+ static USBPacket *p; -+ -+ QTAILQ_FOREACH(p, &ep->queue, queue) { -+ packet_id_queue_add(&dev->already_in_flight, p->id); -+ } -+} -+ -+static void usbredir_fill_already_in_flight(USBRedirDevice *dev) -+{ -+ int ep; -+ struct USBDevice *udev = &dev->dev; -+ -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); -+ -+ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); -+ } -+} -+ -+static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) -+{ -+ return packet_id_queue_remove(&dev->already_in_flight, id); -+} -+ - static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, - uint8_t ep, uint64_t id) - { -@@ -541,6 +570,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, - - DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - bulk_packet.endpoint = ep; - bulk_packet.length = p->iov.size; - bulk_packet.stream_id = 0; -@@ -621,6 +654,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, - p->iov.size, p->id); - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - interrupt_packet.endpoint = ep; - interrupt_packet.length = p->iov.size; - -@@ -763,6 +800,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); - struct usb_redir_control_packet_header control_packet; - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - /* Special cases for certain standard device requests */ - switch (request) { - case DeviceOutRequest | USB_REQ_SET_ADDRESS: -@@ -987,6 +1028,7 @@ static int usbredir_initfn(USBDevice *udev) - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - - packet_id_queue_init(&dev->cancelled, dev, "cancelled"); -+ packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -@@ -1007,6 +1049,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev) - int i; - - packet_id_queue_empty(&dev->cancelled); -+ packet_id_queue_empty(&dev->already_in_flight); - for (i = 0; i < MAX_ENDPOINTS; i++) { - usbredir_free_bufpq(dev, I2EP(i)); - } --- -1.7.12 - diff --git a/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch b/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch new file mode 100644 index 0000000..2efd733 --- /dev/null +++ b/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch @@ -0,0 +1,184 @@ +From efbf5d06a89ec7b329d2aa15d3a6ea023b63c646 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 4 Sep 2012 14:18:34 +0200 +Subject: [PATCH 361/365] usb-redir: Change cancelled packet code into a + generic packet-id queue + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 102 +++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 71 insertions(+), 31 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 9cbcddb..08776d9 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -43,7 +43,6 @@ + #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) + #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) + +-typedef struct Cancelled Cancelled; + typedef struct USBRedirDevice USBRedirDevice; + + /* Struct to hold buffered packets (iso or int input packets) */ +@@ -69,6 +68,18 @@ struct endp_data { + int bufpq_target_size; + }; + ++struct PacketIdQueueEntry { ++ uint64_t id; ++ QTAILQ_ENTRY(PacketIdQueueEntry)next; ++}; ++ ++struct PacketIdQueue { ++ USBRedirDevice *dev; ++ const char *name; ++ QTAILQ_HEAD(, PacketIdQueueEntry) head; ++ int size; ++}; ++ + struct USBRedirDevice { + USBDevice dev; + /* Properties */ +@@ -86,7 +97,7 @@ struct USBRedirDevice { + int64_t next_attach_time; + struct usbredirparser *parser; + struct endp_data endpoint[MAX_ENDPOINTS]; +- QTAILQ_HEAD(, Cancelled) cancelled; ++ struct PacketIdQueue cancelled; + /* Data for device filtering */ + struct usb_redir_device_connect_header device_info; + struct usb_redir_interface_info_header interface_info; +@@ -94,11 +105,6 @@ struct USBRedirDevice { + int filter_rules_count; + }; + +-struct Cancelled { +- uint64_t id; +- QTAILQ_ENTRY(Cancelled)next; +-}; +- + static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); + static void usbredir_device_connect(void *priv, + struct usb_redir_device_connect_header *device_connect); +@@ -249,37 +255,75 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + * Cancelled and buffered packets helpers + */ + +-static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) ++static void packet_id_queue_init(struct PacketIdQueue *q, ++ USBRedirDevice *dev, const char *name) + { +- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); +- Cancelled *c; ++ q->dev = dev; ++ q->name = name; ++ QTAILQ_INIT(&q->head); ++ q->size = 0; ++} ++ ++static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ ++ DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); ++ ++ e = g_malloc0(sizeof(struct PacketIdQueueEntry)); ++ e->id = id; ++ QTAILQ_INSERT_TAIL(&q->head, e, next); ++ q->size++; ++} ++ ++static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ ++ QTAILQ_FOREACH(e, &q->head, next) { ++ if (e->id == id) { ++ DPRINTF("removing packet id %"PRIu64" from %s queue\n", ++ id, q->name); ++ QTAILQ_REMOVE(&q->head, e, next); ++ q->size--; ++ g_free(e); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static void packet_id_queue_empty(struct PacketIdQueue *q) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e, *next_e; + +- DPRINTF("cancel packet id %"PRIu64"\n", p->id); ++ DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name); + +- c = g_malloc0(sizeof(Cancelled)); +- c->id = p->id; +- QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); ++ QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { ++ QTAILQ_REMOVE(&q->head, e, next); ++ g_free(e); ++ } ++ q->size = 0; ++} + ++static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) ++{ ++ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); ++ ++ packet_id_queue_add(&dev->cancelled, p->id); + usbredirparser_send_cancel_data_packet(dev->parser, p->id); + usbredirparser_do_write(dev->parser); + } + + static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) + { +- Cancelled *c; +- + if (!dev->dev.attached) { + return 1; /* Treat everything as cancelled after a disconnect */ + } +- +- QTAILQ_FOREACH(c, &dev->cancelled, next) { +- if (c->id == id) { +- QTAILQ_REMOVE(&dev->cancelled, c, next); +- g_free(c); +- return 1; +- } +- } +- return 0; ++ return packet_id_queue_remove(&dev->cancelled, id); + } + + static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, +@@ -942,7 +986,7 @@ static int usbredir_initfn(USBDevice *udev) + dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + +- QTAILQ_INIT(&dev->cancelled); ++ packet_id_queue_init(&dev->cancelled, dev, "cancelled"); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +@@ -960,13 +1004,9 @@ static int usbredir_initfn(USBDevice *udev) + + static void usbredir_cleanup_device_queues(USBRedirDevice *dev) + { +- Cancelled *c, *next_c; + int i; + +- QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { +- QTAILQ_REMOVE(&dev->cancelled, c, next); +- g_free(c); +- } ++ packet_id_queue_empty(&dev->cancelled); + for (i = 0; i < MAX_ENDPOINTS; i++) { + usbredir_free_bufpq(dev, I2EP(i)); + } +-- +1.7.12 + diff --git a/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch b/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch new file mode 100644 index 0000000..10c9aa3 --- /dev/null +++ b/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch @@ -0,0 +1,119 @@ +From b422d151d0861ed346bed7cddb410a6b4c67711b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 4 Sep 2012 17:03:54 +0200 +Subject: [PATCH 362/365] usb-redir: Add an already_in_flight packet-id queue + +After a live migration, the usb-hcd will re-queue all packets by +walking over the schedule in the guest memory again, but requests which +were encountered on the migration source before will already be in flight, +so these should *not* be re-send to the usbredir-host. + +This patch adds an already in flight packet ud queue, which will be filled by +the source before migration and then moved over to the migration dest, any +async handled packets are then checked against this queue to avoid sending +the same packet to the usbredir-host twice. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 08776d9..1c8edd3 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -98,6 +98,7 @@ struct USBRedirDevice { + struct usbredirparser *parser; + struct endp_data endpoint[MAX_ENDPOINTS]; + struct PacketIdQueue cancelled; ++ struct PacketIdQueue already_in_flight; + /* Data for device filtering */ + struct usb_redir_device_connect_header device_info; + struct usb_redir_interface_info_header interface_info; +@@ -326,6 +327,34 @@ static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) + return packet_id_queue_remove(&dev->cancelled, id); + } + ++static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, ++ struct USBEndpoint *ep) ++{ ++ static USBPacket *p; ++ ++ QTAILQ_FOREACH(p, &ep->queue, queue) { ++ packet_id_queue_add(&dev->already_in_flight, p->id); ++ } ++} ++ ++static void usbredir_fill_already_in_flight(USBRedirDevice *dev) ++{ ++ int ep; ++ struct USBDevice *udev = &dev->dev; ++ ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); ++ ++ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); ++ } ++} ++ ++static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) ++{ ++ return packet_id_queue_remove(&dev->already_in_flight, id); ++} ++ + static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, + uint8_t ep, uint64_t id) + { +@@ -541,6 +570,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, + + DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + bulk_packet.endpoint = ep; + bulk_packet.length = p->iov.size; + bulk_packet.stream_id = 0; +@@ -621,6 +654,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, + DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, + p->iov.size, p->id); + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + interrupt_packet.endpoint = ep; + interrupt_packet.length = p->iov.size; + +@@ -763,6 +800,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + struct usb_redir_control_packet_header control_packet; + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + /* Special cases for certain standard device requests */ + switch (request) { + case DeviceOutRequest | USB_REQ_SET_ADDRESS: +@@ -987,6 +1028,7 @@ static int usbredir_initfn(USBDevice *udev) + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + + packet_id_queue_init(&dev->cancelled, dev, "cancelled"); ++ packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +@@ -1007,6 +1049,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev) + int i; + + packet_id_queue_empty(&dev->cancelled); ++ packet_id_queue_empty(&dev->already_in_flight); + for (i = 0; i < MAX_ENDPOINTS; i++) { + usbredir_free_bufpq(dev, I2EP(i)); + } +-- +1.7.12 + diff --git a/0363-usb-redir-Store-max_packet_size-in-endp_data.patch b/0363-usb-redir-Store-max_packet_size-in-endp_data.patch deleted file mode 100644 index 16f05d3..0000000 --- a/0363-usb-redir-Store-max_packet_size-in-endp_data.patch +++ /dev/null @@ -1,38 +0,0 @@ -From c9917c910cf59e2407bbf51770724c5ec17d9cd1 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 6 Sep 2012 20:52:36 +0200 -Subject: [PATCH 363/365] usb-redir: Store max_packet_size in endp_data - -So that we've a place to migrate it to / from to allow restoring it after -migration. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 1c8edd3..d8568ae 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -57,6 +57,7 @@ struct endp_data { - uint8_t type; - uint8_t interval; - uint8_t interface; /* bInterfaceNumber this ep belongs to */ -+ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ - uint8_t iso_started; - uint8_t iso_error; /* For reporting iso errors to the HC */ - uint8_t interrupt_started; -@@ -1305,7 +1306,8 @@ static void usbredir_ep_info(void *priv, - usb_ep->ifnum = dev->endpoint[i].interface; - if (usbredirparser_peer_has_cap(dev->parser, - usb_redir_cap_ep_info_max_packet_size)) { -- usb_ep->max_packet_size = ep_info->max_packet_size[i]; -+ dev->endpoint[i].max_packet_size = -+ usb_ep->max_packet_size = ep_info->max_packet_size[i]; - } - if (ep_info->type[i] == usb_redir_type_bulk) { - usb_ep->pipeline = true; --- -1.7.12 - diff --git a/0364-usb-redir-Add-support-for-migration.patch b/0364-usb-redir-Add-support-for-migration.patch deleted file mode 100644 index bcbbaab..0000000 --- a/0364-usb-redir-Add-support-for-migration.patch +++ /dev/null @@ -1,429 +0,0 @@ -From 0d733a1280bdaba402c6efbfae116408d7c81bb0 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 09:21:44 +0200 -Subject: [PATCH 364/365] usb-redir: Add support for migration - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 346 insertions(+), 3 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index d8568ae..812096e 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -65,8 +65,8 @@ struct endp_data { - uint8_t bufpq_prefilled; - uint8_t bufpq_dropping_packets; - QTAILQ_HEAD(, buf_packet) bufpq; -- int bufpq_size; -- int bufpq_target_size; -+ int32_t bufpq_size; -+ int32_t bufpq_target_size; - }; - - struct PacketIdQueueEntry { -@@ -241,6 +241,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - return 0; - } - -+ /* Don't send new data to the chardev until our state is fully synced */ -+ if (!runstate_check(RUN_STATE_RUNNING)) { -+ return 0; -+ } -+ - r = qemu_chr_fe_write(dev->cs, data, count); - - if (r < 0) { -@@ -868,6 +873,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - { - uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; - char version[32]; -+ int flags = 0; - - /* Make sure any pending closes are handled (no-op if none pending) */ - usbredir_chardev_close_bh(dev); -@@ -903,7 +909,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); - usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); - usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); -- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); -+ -+ if (runstate_check(RUN_STATE_INMIGRATE)) { -+ flags |= usbredirparser_fl_no_hello; -+ } -+ usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, -+ flags); - usbredirparser_do_write(dev->parser); - } - -@@ -949,6 +960,11 @@ static int usbredir_chardev_can_read(void *opaque) - return 0; - } - -+ /* Don't read new data from the chardev until our state is fully synced */ -+ if (!runstate_check(RUN_STATE_RUNNING)) { -+ return 0; -+ } -+ - /* usbredir_parser_do_read will consume *all* data we give it */ - return 1024 * 1024; - } -@@ -1004,6 +1020,15 @@ static const QemuChrHandlers usbredir_chr_handlers = { - * init + destroy - */ - -+static void usbredir_vm_state_change(void *priv, int running, RunState state) -+{ -+ USBRedirDevice *dev = priv; -+ -+ if (state == RUN_STATE_RUNNING && dev->parser != NULL) { -+ usbredirparser_do_write(dev->parser); /* Flush any pending writes */ -+ } -+} -+ - static int usbredir_initfn(USBDevice *udev) - { - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -@@ -1041,6 +1066,7 @@ static int usbredir_initfn(USBDevice *udev) - qemu_chr_fe_open(dev->cs); - qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); - -+ qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); - add_boot_device_path(dev->bootindex, &udev->qdev, NULL); - return 0; - } -@@ -1530,6 +1556,322 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, - } - } - -+/* -+ * Migration code -+ */ -+ -+static void usbredir_pre_save(void *priv) -+{ -+ USBRedirDevice *dev = priv; -+ -+ usbredir_fill_already_in_flight(dev); -+} -+ -+static int usbredir_post_load(void *priv, int version_id) -+{ -+ USBRedirDevice *dev = priv; -+ struct USBEndpoint *usb_ep; -+ int i; -+ -+ switch (dev->device_info.speed) { -+ case usb_redir_speed_low: -+ dev->dev.speed = USB_SPEED_LOW; -+ break; -+ case usb_redir_speed_full: -+ dev->dev.speed = USB_SPEED_FULL; -+ break; -+ case usb_redir_speed_high: -+ dev->dev.speed = USB_SPEED_HIGH; -+ break; -+ case usb_redir_speed_super: -+ dev->dev.speed = USB_SPEED_SUPER; -+ break; -+ default: -+ dev->dev.speed = USB_SPEED_FULL; -+ } -+ dev->dev.speedmask = (1 << dev->dev.speed); -+ -+ for (i = 0; i < MAX_ENDPOINTS; i++) { -+ usb_ep = usb_ep_get(&dev->dev, -+ (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, -+ i & 0x0f); -+ usb_ep->type = dev->endpoint[i].type; -+ usb_ep->ifnum = dev->endpoint[i].interface; -+ usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; -+ if (dev->endpoint[i].type == usb_redir_type_bulk) { -+ usb_ep->pipeline = true; -+ } -+ } -+ return 0; -+} -+ -+/* For usbredirparser migration */ -+static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) -+{ -+ USBRedirDevice *dev = priv; -+ uint8_t *data; -+ int len; -+ -+ if (dev->parser == NULL) { -+ qemu_put_be32(f, 0); -+ return; -+ } -+ -+ usbredirparser_serialize(dev->parser, &data, &len); -+ qemu_oom_check(data); -+ -+ qemu_put_be32(f, len); -+ qemu_put_buffer(f, data, len); -+ -+ free(data); -+} -+ -+static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) -+{ -+ USBRedirDevice *dev = priv; -+ uint8_t *data; -+ int len, ret; -+ -+ len = qemu_get_be32(f); -+ if (len == 0) { -+ return 0; -+ } -+ -+ /* -+ * Our chardev should be open already at this point, otherwise -+ * the usbredir channel will be broken (ie spice without seamless) -+ */ -+ if (dev->parser == NULL) { -+ ERROR("get_parser called with closed chardev, failing migration\n"); -+ return -1; -+ } -+ -+ data = g_malloc(len); -+ qemu_get_buffer(f, data, len); -+ -+ ret = usbredirparser_unserialize(dev->parser, data, len); -+ -+ g_free(data); -+ -+ return ret; -+} -+ -+static const VMStateInfo usbredir_parser_vmstate_info = { -+ .name = "usb-redir-parser", -+ .put = usbredir_put_parser, -+ .get = usbredir_get_parser, -+}; -+ -+ -+/* For buffered packets (iso/irq) queue migration */ -+static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct endp_data *endp = priv; -+ struct buf_packet *bufp; -+ int remain = endp->bufpq_size; -+ -+ qemu_put_be32(f, endp->bufpq_size); -+ QTAILQ_FOREACH(bufp, &endp->bufpq, next) { -+ qemu_put_be32(f, bufp->len); -+ qemu_put_be32(f, bufp->status); -+ qemu_put_buffer(f, bufp->data, bufp->len); -+ remain--; -+ } -+ assert(remain == 0); -+} -+ -+static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct endp_data *endp = priv; -+ struct buf_packet *bufp; -+ int i; -+ -+ endp->bufpq_size = qemu_get_be32(f); -+ for (i = 0; i < endp->bufpq_size; i++) { -+ bufp = g_malloc(sizeof(struct buf_packet)); -+ bufp->len = qemu_get_be32(f); -+ bufp->status = qemu_get_be32(f); -+ bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ -+ qemu_get_buffer(f, bufp->data, bufp->len); -+ QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); -+ } -+ return 0; -+} -+ -+static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { -+ .name = "usb-redir-bufpq", -+ .put = usbredir_put_bufpq, -+ .get = usbredir_get_bufpq, -+}; -+ -+ -+/* For endp_data migration */ -+static const VMStateDescription usbredir_ep_vmstate = { -+ .name = "usb-redir-ep", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT8(type, struct endp_data), -+ VMSTATE_UINT8(interval, struct endp_data), -+ VMSTATE_UINT8(interface, struct endp_data), -+ VMSTATE_UINT16(max_packet_size, struct endp_data), -+ VMSTATE_UINT8(iso_started, struct endp_data), -+ VMSTATE_UINT8(iso_error, struct endp_data), -+ VMSTATE_UINT8(interrupt_started, struct endp_data), -+ VMSTATE_UINT8(interrupt_error, struct endp_data), -+ VMSTATE_UINT8(bufpq_prefilled, struct endp_data), -+ VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data), -+ { -+ .name = "bufpq", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_ep_bufpq_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_INT32(bufpq_target_size, struct endp_data), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For PacketIdQueue migration */ -+static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct PacketIdQueue *q = priv; -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ int remain = q->size; -+ -+ DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size); -+ qemu_put_be32(f, q->size); -+ QTAILQ_FOREACH(e, &q->head, next) { -+ qemu_put_be64(f, e->id); -+ remain--; -+ } -+ assert(remain == 0); -+} -+ -+static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct PacketIdQueue *q = priv; -+ USBRedirDevice *dev = q->dev; -+ int i, size; -+ uint64_t id; -+ -+ size = qemu_get_be32(f); -+ DPRINTF("get_packet_id_q %s size %d\n", q->name, size); -+ for (i = 0; i < size; i++) { -+ id = qemu_get_be64(f); -+ packet_id_queue_add(q, id); -+ } -+ assert(q->size == size); -+ return 0; -+} -+ -+static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { -+ .name = "usb-redir-packet-id-q", -+ .put = usbredir_put_packet_id_q, -+ .get = usbredir_get_packet_id_q, -+}; -+ -+static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { -+ .name = "usb-redir-packet-id-queue", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ { -+ .name = "queue", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_ep_packet_id_q_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For usb_redir_device_connect_header migration */ -+static const VMStateDescription usbredir_device_info_vmstate = { -+ .name = "usb-redir-device-info", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT8(speed, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(device_version_bcd, -+ struct usb_redir_device_connect_header), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For usb_redir_interface_info_header migration */ -+static const VMStateDescription usbredir_interface_info_vmstate = { -+ .name = "usb-redir-interface-info", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT32(interface_count, -+ struct usb_redir_interface_info_header), -+ VMSTATE_UINT8_ARRAY(interface, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_class, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_subclass, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_protocol, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* And finally the USBRedirDevice vmstate itself */ -+static const VMStateDescription usbredir_vmstate = { -+ .name = "usb-redir", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = usbredir_pre_save, -+ .post_load = usbredir_post_load, -+ .fields = (VMStateField []) { -+ VMSTATE_USB_DEVICE(dev, USBRedirDevice), -+ VMSTATE_TIMER(attach_timer, USBRedirDevice), -+ { -+ .name = "parser", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_parser_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1, -+ usbredir_ep_vmstate, struct endp_data), -+ VMSTATE_STRUCT(cancelled, USBRedirDevice, 1, -+ usbredir_ep_packet_id_queue_vmstate, -+ struct PacketIdQueue), -+ VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1, -+ usbredir_ep_packet_id_queue_vmstate, -+ struct PacketIdQueue), -+ VMSTATE_STRUCT(device_info, USBRedirDevice, 1, -+ usbredir_device_info_vmstate, -+ struct usb_redir_device_connect_header), -+ VMSTATE_STRUCT(interface_info, USBRedirDevice, 1, -+ usbredir_interface_info_vmstate, -+ struct usb_redir_interface_info_header), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ - static Property usbredir_properties[] = { - DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), - DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), -@@ -1550,6 +1892,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) - uc->handle_reset = usbredir_handle_reset; - uc->handle_data = usbredir_handle_data; - uc->handle_control = usbredir_handle_control; -+ dc->vmsd = &usbredir_vmstate; - dc->props = usbredir_properties; - } - --- -1.7.12 - diff --git a/0364-usb-redir-Store-max_packet_size-in-endp_data.patch b/0364-usb-redir-Store-max_packet_size-in-endp_data.patch new file mode 100644 index 0000000..16f05d3 --- /dev/null +++ b/0364-usb-redir-Store-max_packet_size-in-endp_data.patch @@ -0,0 +1,38 @@ +From c9917c910cf59e2407bbf51770724c5ec17d9cd1 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 6 Sep 2012 20:52:36 +0200 +Subject: [PATCH 363/365] usb-redir: Store max_packet_size in endp_data + +So that we've a place to migrate it to / from to allow restoring it after +migration. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 1c8edd3..d8568ae 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -57,6 +57,7 @@ struct endp_data { + uint8_t type; + uint8_t interval; + uint8_t interface; /* bInterfaceNumber this ep belongs to */ ++ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ + uint8_t iso_started; + uint8_t iso_error; /* For reporting iso errors to the HC */ + uint8_t interrupt_started; +@@ -1305,7 +1306,8 @@ static void usbredir_ep_info(void *priv, + usb_ep->ifnum = dev->endpoint[i].interface; + if (usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_ep_info_max_packet_size)) { +- usb_ep->max_packet_size = ep_info->max_packet_size[i]; ++ dev->endpoint[i].max_packet_size = ++ usb_ep->max_packet_size = ep_info->max_packet_size[i]; + } + if (ep_info->type[i] == usb_redir_type_bulk) { + usb_ep->pipeline = true; +-- +1.7.12 + diff --git a/0365-usb-redir-Add-chardev-open-close-debug-logging.patch b/0365-usb-redir-Add-chardev-open-close-debug-logging.patch deleted file mode 100644 index 4e2f75d..0000000 --- a/0365-usb-redir-Add-chardev-open-close-debug-logging.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 3efd9345ea643cf6f15776425213a92a442dd217 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 15:56:57 +0200 -Subject: [PATCH 365/365] usb-redir: Add chardev open / close debug logging - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 812096e..b03c412 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -864,6 +864,7 @@ static void usbredir_chardev_close_bh(void *opaque) - usbredir_device_disconnect(dev); - - if (dev->parser) { -+ DPRINTF("destroying usbredirparser\n"); - usbredirparser_destroy(dev->parser); - dev->parser = NULL; - } -@@ -879,6 +880,8 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - usbredir_chardev_close_bh(dev); - qemu_bh_cancel(dev->chardev_close_bh); - -+ DPRINTF("creating usbredirparser\n"); -+ - strcpy(version, "qemu usb-redir guest "); - pstrcat(version, sizeof(version), qemu_get_version()); - -@@ -990,9 +993,11 @@ static void usbredir_chardev_event(void *opaque, int event) - - switch (event) { - case CHR_EVENT_OPENED: -+ DPRINTF("chardev open\n"); - usbredir_chardev_open(dev); - break; - case CHR_EVENT_CLOSED: -+ DPRINTF("chardev close\n"); - qemu_bh_schedule(dev->chardev_close_bh); - break; - } -@@ -1255,6 +1260,7 @@ static void usbredir_device_disconnect(void *priv) - qemu_del_timer(dev->attach_timer); - - if (dev->dev.attached) { -+ DPRINTF("detaching device\n"); - usb_device_detach(&dev->dev); - /* - * Delay next usb device attach to give the guest a chance to see --- -1.7.12 - diff --git a/0365-usb-redir-Add-support-for-migration.patch b/0365-usb-redir-Add-support-for-migration.patch new file mode 100644 index 0000000..bcbbaab --- /dev/null +++ b/0365-usb-redir-Add-support-for-migration.patch @@ -0,0 +1,429 @@ +From 0d733a1280bdaba402c6efbfae116408d7c81bb0 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 5 Sep 2012 09:21:44 +0200 +Subject: [PATCH 364/365] usb-redir: Add support for migration + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 346 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index d8568ae..812096e 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -65,8 +65,8 @@ struct endp_data { + uint8_t bufpq_prefilled; + uint8_t bufpq_dropping_packets; + QTAILQ_HEAD(, buf_packet) bufpq; +- int bufpq_size; +- int bufpq_target_size; ++ int32_t bufpq_size; ++ int32_t bufpq_target_size; + }; + + struct PacketIdQueueEntry { +@@ -241,6 +241,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + return 0; + } + ++ /* Don't send new data to the chardev until our state is fully synced */ ++ if (!runstate_check(RUN_STATE_RUNNING)) { ++ return 0; ++ } ++ + r = qemu_chr_fe_write(dev->cs, data, count); + + if (r < 0) { +@@ -868,6 +873,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + { + uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; + char version[32]; ++ int flags = 0; + + /* Make sure any pending closes are handled (no-op if none pending) */ + usbredir_chardev_close_bh(dev); +@@ -903,7 +909,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); + usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); + usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); +- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); ++ ++ if (runstate_check(RUN_STATE_INMIGRATE)) { ++ flags |= usbredirparser_fl_no_hello; ++ } ++ usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, ++ flags); + usbredirparser_do_write(dev->parser); + } + +@@ -949,6 +960,11 @@ static int usbredir_chardev_can_read(void *opaque) + return 0; + } + ++ /* Don't read new data from the chardev until our state is fully synced */ ++ if (!runstate_check(RUN_STATE_RUNNING)) { ++ return 0; ++ } ++ + /* usbredir_parser_do_read will consume *all* data we give it */ + return 1024 * 1024; + } +@@ -1004,6 +1020,15 @@ static const QemuChrHandlers usbredir_chr_handlers = { + * init + destroy + */ + ++static void usbredir_vm_state_change(void *priv, int running, RunState state) ++{ ++ USBRedirDevice *dev = priv; ++ ++ if (state == RUN_STATE_RUNNING && dev->parser != NULL) { ++ usbredirparser_do_write(dev->parser); /* Flush any pending writes */ ++ } ++} ++ + static int usbredir_initfn(USBDevice *udev) + { + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); +@@ -1041,6 +1066,7 @@ static int usbredir_initfn(USBDevice *udev) + qemu_chr_fe_open(dev->cs); + qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); + ++ qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); + add_boot_device_path(dev->bootindex, &udev->qdev, NULL); + return 0; + } +@@ -1530,6 +1556,322 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, + } + } + ++/* ++ * Migration code ++ */ ++ ++static void usbredir_pre_save(void *priv) ++{ ++ USBRedirDevice *dev = priv; ++ ++ usbredir_fill_already_in_flight(dev); ++} ++ ++static int usbredir_post_load(void *priv, int version_id) ++{ ++ USBRedirDevice *dev = priv; ++ struct USBEndpoint *usb_ep; ++ int i; ++ ++ switch (dev->device_info.speed) { ++ case usb_redir_speed_low: ++ dev->dev.speed = USB_SPEED_LOW; ++ break; ++ case usb_redir_speed_full: ++ dev->dev.speed = USB_SPEED_FULL; ++ break; ++ case usb_redir_speed_high: ++ dev->dev.speed = USB_SPEED_HIGH; ++ break; ++ case usb_redir_speed_super: ++ dev->dev.speed = USB_SPEED_SUPER; ++ break; ++ default: ++ dev->dev.speed = USB_SPEED_FULL; ++ } ++ dev->dev.speedmask = (1 << dev->dev.speed); ++ ++ for (i = 0; i < MAX_ENDPOINTS; i++) { ++ usb_ep = usb_ep_get(&dev->dev, ++ (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, ++ i & 0x0f); ++ usb_ep->type = dev->endpoint[i].type; ++ usb_ep->ifnum = dev->endpoint[i].interface; ++ usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; ++ if (dev->endpoint[i].type == usb_redir_type_bulk) { ++ usb_ep->pipeline = true; ++ } ++ } ++ return 0; ++} ++ ++/* For usbredirparser migration */ ++static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) ++{ ++ USBRedirDevice *dev = priv; ++ uint8_t *data; ++ int len; ++ ++ if (dev->parser == NULL) { ++ qemu_put_be32(f, 0); ++ return; ++ } ++ ++ usbredirparser_serialize(dev->parser, &data, &len); ++ qemu_oom_check(data); ++ ++ qemu_put_be32(f, len); ++ qemu_put_buffer(f, data, len); ++ ++ free(data); ++} ++ ++static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) ++{ ++ USBRedirDevice *dev = priv; ++ uint8_t *data; ++ int len, ret; ++ ++ len = qemu_get_be32(f); ++ if (len == 0) { ++ return 0; ++ } ++ ++ /* ++ * Our chardev should be open already at this point, otherwise ++ * the usbredir channel will be broken (ie spice without seamless) ++ */ ++ if (dev->parser == NULL) { ++ ERROR("get_parser called with closed chardev, failing migration\n"); ++ return -1; ++ } ++ ++ data = g_malloc(len); ++ qemu_get_buffer(f, data, len); ++ ++ ret = usbredirparser_unserialize(dev->parser, data, len); ++ ++ g_free(data); ++ ++ return ret; ++} ++ ++static const VMStateInfo usbredir_parser_vmstate_info = { ++ .name = "usb-redir-parser", ++ .put = usbredir_put_parser, ++ .get = usbredir_get_parser, ++}; ++ ++ ++/* For buffered packets (iso/irq) queue migration */ ++static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct endp_data *endp = priv; ++ struct buf_packet *bufp; ++ int remain = endp->bufpq_size; ++ ++ qemu_put_be32(f, endp->bufpq_size); ++ QTAILQ_FOREACH(bufp, &endp->bufpq, next) { ++ qemu_put_be32(f, bufp->len); ++ qemu_put_be32(f, bufp->status); ++ qemu_put_buffer(f, bufp->data, bufp->len); ++ remain--; ++ } ++ assert(remain == 0); ++} ++ ++static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct endp_data *endp = priv; ++ struct buf_packet *bufp; ++ int i; ++ ++ endp->bufpq_size = qemu_get_be32(f); ++ for (i = 0; i < endp->bufpq_size; i++) { ++ bufp = g_malloc(sizeof(struct buf_packet)); ++ bufp->len = qemu_get_be32(f); ++ bufp->status = qemu_get_be32(f); ++ bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ ++ qemu_get_buffer(f, bufp->data, bufp->len); ++ QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); ++ } ++ return 0; ++} ++ ++static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { ++ .name = "usb-redir-bufpq", ++ .put = usbredir_put_bufpq, ++ .get = usbredir_get_bufpq, ++}; ++ ++ ++/* For endp_data migration */ ++static const VMStateDescription usbredir_ep_vmstate = { ++ .name = "usb-redir-ep", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT8(type, struct endp_data), ++ VMSTATE_UINT8(interval, struct endp_data), ++ VMSTATE_UINT8(interface, struct endp_data), ++ VMSTATE_UINT16(max_packet_size, struct endp_data), ++ VMSTATE_UINT8(iso_started, struct endp_data), ++ VMSTATE_UINT8(iso_error, struct endp_data), ++ VMSTATE_UINT8(interrupt_started, struct endp_data), ++ VMSTATE_UINT8(interrupt_error, struct endp_data), ++ VMSTATE_UINT8(bufpq_prefilled, struct endp_data), ++ VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data), ++ { ++ .name = "bufpq", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_ep_bufpq_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_INT32(bufpq_target_size, struct endp_data), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For PacketIdQueue migration */ ++static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct PacketIdQueue *q = priv; ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ int remain = q->size; ++ ++ DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size); ++ qemu_put_be32(f, q->size); ++ QTAILQ_FOREACH(e, &q->head, next) { ++ qemu_put_be64(f, e->id); ++ remain--; ++ } ++ assert(remain == 0); ++} ++ ++static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct PacketIdQueue *q = priv; ++ USBRedirDevice *dev = q->dev; ++ int i, size; ++ uint64_t id; ++ ++ size = qemu_get_be32(f); ++ DPRINTF("get_packet_id_q %s size %d\n", q->name, size); ++ for (i = 0; i < size; i++) { ++ id = qemu_get_be64(f); ++ packet_id_queue_add(q, id); ++ } ++ assert(q->size == size); ++ return 0; ++} ++ ++static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { ++ .name = "usb-redir-packet-id-q", ++ .put = usbredir_put_packet_id_q, ++ .get = usbredir_get_packet_id_q, ++}; ++ ++static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { ++ .name = "usb-redir-packet-id-queue", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ { ++ .name = "queue", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_ep_packet_id_q_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For usb_redir_device_connect_header migration */ ++static const VMStateDescription usbredir_device_info_vmstate = { ++ .name = "usb-redir-device-info", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT8(speed, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(device_version_bcd, ++ struct usb_redir_device_connect_header), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For usb_redir_interface_info_header migration */ ++static const VMStateDescription usbredir_interface_info_vmstate = { ++ .name = "usb-redir-interface-info", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT32(interface_count, ++ struct usb_redir_interface_info_header), ++ VMSTATE_UINT8_ARRAY(interface, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_class, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_subclass, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_protocol, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* And finally the USBRedirDevice vmstate itself */ ++static const VMStateDescription usbredir_vmstate = { ++ .name = "usb-redir", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = usbredir_pre_save, ++ .post_load = usbredir_post_load, ++ .fields = (VMStateField []) { ++ VMSTATE_USB_DEVICE(dev, USBRedirDevice), ++ VMSTATE_TIMER(attach_timer, USBRedirDevice), ++ { ++ .name = "parser", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_parser_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1, ++ usbredir_ep_vmstate, struct endp_data), ++ VMSTATE_STRUCT(cancelled, USBRedirDevice, 1, ++ usbredir_ep_packet_id_queue_vmstate, ++ struct PacketIdQueue), ++ VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1, ++ usbredir_ep_packet_id_queue_vmstate, ++ struct PacketIdQueue), ++ VMSTATE_STRUCT(device_info, USBRedirDevice, 1, ++ usbredir_device_info_vmstate, ++ struct usb_redir_device_connect_header), ++ VMSTATE_STRUCT(interface_info, USBRedirDevice, 1, ++ usbredir_interface_info_vmstate, ++ struct usb_redir_interface_info_header), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + static Property usbredir_properties[] = { + DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), + DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), +@@ -1550,6 +1892,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) + uc->handle_reset = usbredir_handle_reset; + uc->handle_data = usbredir_handle_data; + uc->handle_control = usbredir_handle_control; ++ dc->vmsd = &usbredir_vmstate; + dc->props = usbredir_properties; + } + +-- +1.7.12 + diff --git a/0366-usb-redir-Add-chardev-open-close-debug-logging.patch b/0366-usb-redir-Add-chardev-open-close-debug-logging.patch new file mode 100644 index 0000000..4e2f75d --- /dev/null +++ b/0366-usb-redir-Add-chardev-open-close-debug-logging.patch @@ -0,0 +1,54 @@ +From 3efd9345ea643cf6f15776425213a92a442dd217 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 5 Sep 2012 15:56:57 +0200 +Subject: [PATCH 365/365] usb-redir: Add chardev open / close debug logging + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 812096e..b03c412 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -864,6 +864,7 @@ static void usbredir_chardev_close_bh(void *opaque) + usbredir_device_disconnect(dev); + + if (dev->parser) { ++ DPRINTF("destroying usbredirparser\n"); + usbredirparser_destroy(dev->parser); + dev->parser = NULL; + } +@@ -879,6 +880,8 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + usbredir_chardev_close_bh(dev); + qemu_bh_cancel(dev->chardev_close_bh); + ++ DPRINTF("creating usbredirparser\n"); ++ + strcpy(version, "qemu usb-redir guest "); + pstrcat(version, sizeof(version), qemu_get_version()); + +@@ -990,9 +993,11 @@ static void usbredir_chardev_event(void *opaque, int event) + + switch (event) { + case CHR_EVENT_OPENED: ++ DPRINTF("chardev open\n"); + usbredir_chardev_open(dev); + break; + case CHR_EVENT_CLOSED: ++ DPRINTF("chardev close\n"); + qemu_bh_schedule(dev->chardev_close_bh); + break; + } +@@ -1255,6 +1260,7 @@ static void usbredir_device_disconnect(void *priv) + qemu_del_timer(dev->attach_timer); + + if (dev->dev.attached) { ++ DPRINTF("detaching device\n"); + usb_device_detach(&dev->dev); + /* + * Delay next usb device attach to give the guest a chance to see +-- +1.7.12 + diff --git a/0367-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch b/0367-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch new file mode 100644 index 0000000..8a1b518 --- /dev/null +++ b/0367-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch @@ -0,0 +1,63 @@ +From 786657ed32cb68ae5cd4d099e6ea3f36290bcbcb Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 10 Sep 2012 13:49:46 +0200 +Subject: [PATCH 367/369] usb-redir: Revert usb-redir part of commit 93bfef4c + +Commit 93bfef4c6e4b23caea9d51e1099d06433d8835a4 makes qemu-devices +which report the qemu version string to the guest in some way use a +qemu_get_version function which reports a machine-specific version string. + +However usb-redir does not expose the qemu version to the guest, only to +the usbredir-host as part of the initial handshake. This can then be logged +on the usbredir-host side for debugging purposes and is otherwise completely +unused! For debugging purposes it is important to have the real qemu version +in there, rather then the machine-specific version. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 86c0398..78e93a7 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -142,6 +142,8 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, + static int usbredir_handle_status(USBRedirDevice *dev, + int status, int actual_len); + ++#define VERSION "qemu usb-redir guest " QEMU_VERSION ++ + /* + * Logging stuff + */ +@@ -873,7 +875,6 @@ static void usbredir_chardev_close_bh(void *opaque) + static void usbredir_chardev_open(USBRedirDevice *dev) + { + uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; +- char version[32]; + int flags = 0; + + /* Make sure any pending closes are handled (no-op if none pending) */ +@@ -882,9 +883,6 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + + DPRINTF("creating usbredirparser\n"); + +- strcpy(version, "qemu usb-redir guest "); +- pstrcat(version, sizeof(version), qemu_get_version()); +- + dev->parser = qemu_oom_check(usbredirparser_create()); + dev->parser->priv = dev; + dev->parser->log_func = usbredir_log; +@@ -916,7 +914,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + if (runstate_check(RUN_STATE_INMIGRATE)) { + flags |= usbredirparser_fl_no_hello; + } +- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, ++ usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, + flags); + usbredirparser_do_write(dev->parser); + } +-- +1.7.12 + diff --git a/0368-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch b/0368-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch new file mode 100644 index 0000000..af350d9 --- /dev/null +++ b/0368-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch @@ -0,0 +1,44 @@ +From 41f5d67c0649d74b505edc2a874c91148355eb25 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 12 Sep 2012 13:30:51 +0200 +Subject: [PATCH 368/369] uhci: Don't queue up packets after one with the SPD + flag set + +Don't queue up packets after a packet with the SPD (short packet detect) +flag set. Since we won't know if the packet will actually be short until it +has completed, and if it is short we should stop the queue. + +This fixes a miniature photoframe emulating a USB cdrom with the windows +software for it not working. + +Signed-off-by: Hans de Goede +--- + hw/usb/hcd-uhci.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c +index c7c8786..cdc8bc3 100644 +--- a/hw/usb/hcd-uhci.c ++++ b/hw/usb/hcd-uhci.c +@@ -1000,6 +1000,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) + } + assert(ret == TD_RESULT_ASYNC_START); + assert(int_mask == 0); ++ if (ptd.ctrl & TD_CTRL_SPD) { ++ break; ++ } + plink = ptd.link; + } + } +@@ -1097,7 +1100,7 @@ static void uhci_process_frame(UHCIState *s) + + case TD_RESULT_ASYNC_START: + trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); +- if (is_valid(td.link)) { ++ if (is_valid(td.link) && !(td.ctrl & TD_CTRL_SPD)) { + uhci_fill_queue(s, &td); + } + link = curr_qh ? qh.link : td.link; +-- +1.7.12 + diff --git a/0369-ehci-Fix-interrupt-packet-MULT-handling.patch b/0369-ehci-Fix-interrupt-packet-MULT-handling.patch new file mode 100644 index 0000000..3105ad9 --- /dev/null +++ b/0369-ehci-Fix-interrupt-packet-MULT-handling.patch @@ -0,0 +1,131 @@ +From 074e4dddddec4456026e211163e0d8d5c9bfaf0c Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 20 Sep 2012 16:55:02 +0200 +Subject: [PATCH 369/369] ehci: Fix interrupt packet MULT handling + +There are several issues with our handling of the MULT epcap field +of interrupt qhs, which this patch fixes. + +1) When we don't execute a transaction because of the transaction counter +being 0, p->async stays EHCI_ASYNC_NONE, and the next time we process the +same qtd we hit an assert in ehci_state_fetchqtd because of this. Even though +I believe that this is caused by 3 below, this patch still removes the assert, +as that can still happen without 3, when multiple packets are queued for the +same interrupt ep. + +2) We only *check* the transaction counter from ehci_state_execute, any +packets queued up by fill_queue bypass this check. This is fixed by not calling +fill_queue for interrupt packets. + +3) Some versions of Windows set the MULT field of the qh to 0, which is a +clear violation of the EHCI spec, but still they do it. This means that we +will never execute a qtd for these, making interrupt ep-s on USB-2 devices +not work, and after recent changes, triggering 1). + +So far we've stored the transaction counter in our copy of the mult field, +but with this beginnig at 0 already when dealing with these version of windows +this won't work. So this patch adds a transact_ctr field to our qh struct, +and sets this to the MULT field value on fetchqh. When the MULT field value +is 0, we set it to 4. Assuming that windows gets way with setting it to 0, +by the actual hardware going horizontal on a 1 -> 0 transition, which will +give it 4 transactions (MULT goes from 0 - 3). + +Note that we cannot stop on detecting the 1 -> 0 transition, as our decrement +of the transaction counter, and checking for it are done in 2 different places. + +Reported-by: Shawn Starr +Signed-off-by: Hans de Goede +--- + hw/usb/hcd-ehci.c | 39 +++++++++++++++++++-------------------- + 1 file changed, 19 insertions(+), 20 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 48a1b09..3acd881a 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -373,6 +373,7 @@ struct EHCIQueue { + uint32_t seen; + uint64_t ts; + int async; ++ int transact_ctr; + + /* cached data from guest - needs to be flushed + * when guest removes an entry (doorbell, handshake sequence) +@@ -1837,6 +1838,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + } + q->qh = qh; + ++ q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT); ++ if (q->transact_ctr == 0) /* Guest bug in some versions of windows */ ++ q->transact_ctr = 4; ++ + if (q->dev == NULL) { + q->dev = ehci_find_device(q->ehci, devaddr); + } +@@ -2014,11 +2019,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q) + } else if (p != NULL) { + switch (p->async) { + case EHCI_ASYNC_NONE: +- /* Should never happen packet should at least be initialized */ +- assert(0); +- break; + case EHCI_ASYNC_INITIALIZED: +- /* Previously nacked packet (likely interrupt ep) */ ++ /* Not yet executed (MULT), or previously nacked (int) packet */ + ehci_set_state(q->ehci, q->async, EST_EXECUTE); + break; + case EHCI_ASYNC_INFLIGHT: +@@ -2107,15 +2109,12 @@ static int ehci_state_execute(EHCIQueue *q) + + // TODO verify enough time remains in the uframe as in 4.4.1.1 + // TODO write back ptr to async list when done or out of time +- // TODO Windows does not seem to ever set the MULT field + +- if (!q->async) { +- int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); +- if (!transactCtr) { +- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); +- again = 1; +- goto out; +- } ++ /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */ ++ if (!q->async && q->transact_ctr == 0) { ++ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); ++ again = 1; ++ goto out; + } + + if (q->async) { +@@ -2132,7 +2131,11 @@ static int ehci_state_execute(EHCIQueue *q) + trace_usb_ehci_packet_action(p->queue, p, "async"); + p->async = EHCI_ASYNC_INFLIGHT; + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); +- again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; ++ if (q->async) { ++ again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; ++ } else { ++ again = 1; ++ } + goto out; + } + +@@ -2152,13 +2155,9 @@ static int ehci_state_executing(EHCIQueue *q) + + ehci_execute_complete(q); + +- // 4.10.3 +- if (!q->async) { +- int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); +- transactCtr--; +- set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT); +- // 4.10.3, bottom of page 82, should exit this state when transaction +- // counter decrements to 0 ++ /* 4.10.3 */ ++ if (!q->async && q->transact_ctr > 0) { ++ q->transact_ctr--; + } + + /* 4.10.5 */ +-- +1.7.12 + diff --git a/qemu.spec b/qemu.spec index cdb6fae..e06b79e 100644 --- a/qemu.spec +++ b/qemu.spec @@ -39,7 +39,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 1.2.0 -Release: 8%{?dist} +Release: 9%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD @@ -116,8 +116,16 @@ Patch211: 0211-configure-print-spice-protocol-and-spice-server-vers.patch Patch212: 0212-spice-make-number-of-surfaces-runtime-configurable.patch Patch213: 0213-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch Patch214: 0214-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch -Patch215: 0215-qxl-dont-update-invalid-area.patch -Patch216: 0216-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch +Patch215: 0215-spice-switch-to-queue-for-vga-mode-updates.patch +Patch216: 0216-spice-split-qemu_spice_create_update.patch +Patch217: 0217-spice-add-screen-mirror.patch +Patch218: 0218-spice-send-updates-only-for-changed-screen-content.patch +Patch219: 0219-qxl-dont-update-invalid-area.patch +Patch220: 0220-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch +Patch221: 0221-qxl-better-cleanup-for-surface-destroy.patch +Patch222: 0222-hw-qxl-tracing-fixes.patch +Patch223: 0223-qxl-add-trace-event-for-QXL_IO_LOG.patch +Patch224: 0224-hw-qxl-support-client-monitor-configuration-via-devi.patch # Ugh, ton of USB bugfixes / preparation patches for usb-redir # live-migration which did not make 1.2.0 :| @@ -176,20 +184,23 @@ Patch0351: 0351-xhci-pick-target-interrupter.patch Patch0352: 0352-xhci-support-multiple-interrupters.patch Patch0353: 0353-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch Patch0354: 0354-xhci-allow-bytewise-capability-register-reads.patch -Patch0355: 0355-ehci-switch-to-new-style-memory-ops.patch -Patch0356: 0356-xhci-drop-unused-wlength.patch -Patch0357: 0357-usb-host-allow-emulated-non-async-control-requests-w.patch - +Patch0355: 0355-usb-host-allow-emulated-non-async-control-requests-w.patch +Patch0356: 0356-ehci-switch-to-new-style-memory-ops.patch +Patch0357: 0357-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch +Patch0358: 0358-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch +Patch0359: 0359-configure-usbredir-fixes.patch +Patch0360: 0360-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch +Patch0361: 0361-ehci-Walk-async-schedule-before-and-after-migration.patch +Patch0362: 0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch +Patch0363: 0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch +Patch0364: 0364-usb-redir-Store-max_packet_size-in-endp_data.patch +Patch0365: 0365-usb-redir-Add-support-for-migration.patch +Patch0366: 0366-usb-redir-Add-chardev-open-close-debug-logging.patch +Patch0367: 0367-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch +Patch0368: 0368-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch # And the last few ehci fixes + the actual usb-redir live migration code # Not yet upstream but should get there real soon -Patch0358: 0358-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch -Patch0359: 0359-ehci-Walk-async-schedule-before-and-after-migration.patch -Patch0360: 0360-ehci-Don-t-process-too-much-frames-in-1-timer-tick.patch -Patch0361: 0361-usb-redir-Change-cancelled-packet-code-into-a-generi.patch -Patch0362: 0362-usb-redir-Add-an-already_in_flight-packet-id-queue.patch -Patch0363: 0363-usb-redir-Store-max_packet_size-in-endp_data.patch -Patch0364: 0364-usb-redir-Add-support-for-migration.patch -Patch0365: 0365-usb-redir-Add-chardev-open-close-debug-logging.patch +Patch0369: 0369-ehci-Fix-interrupt-packet-MULT-handling.patch # Revert c3767ed0eb5d0. # NOT upstream (hopefully will be soon). @@ -510,6 +521,14 @@ such as kvm_stat. %patch214 -p1 %patch215 -p1 %patch216 -p1 +%patch217 -p1 +%patch218 -p1 +%patch219 -p1 +%patch220 -p1 +%patch221 -p1 +%patch222 -p1 +%patch223 -p1 +%patch224 -p1 %patch301 -p1 %patch302 -p1 @@ -576,6 +595,10 @@ such as kvm_stat. %patch363 -p1 %patch364 -p1 %patch365 -p1 +%patch366 -p1 +%patch367 -p1 +%patch368 -p1 +%patch369 -p1 %patch900 -p1 @@ -1046,6 +1069,9 @@ fi %{_mandir}/man1/qemu-img.1* %changelog +* Thu Sep 20 2012 Hans de Goede - 2:1.2.0-9 +- Sync USB and Spice patchsets with upstream + * Sun Sep 16 2012 Richard W.M. Jones - 2:1.2.0-8 - Use 'global' instead of 'define', and underscore in definition name, n-v-r, and 'dist' tag of SLOF, all to fix RHBZ#855252.