New upstream release 1.2.0 final
- Add support for Spice seamless migration - Add support for Spice dynamic monitors - Add support for usb-redir live migration
This commit is contained in:
parent
9acdac90af
commit
c8dfc65f53
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,3 +15,4 @@ qemu-kvm-0.13.0-25fdf4a.tar.gz
|
||||
/qemu-1.2-0.1.20120806git3e430569.fc18.src.rpm
|
||||
/qemu-kvm-1.2-3e430569.tar.gz
|
||||
/qemu-kvm-1.2.0-rc1.tar.gz
|
||||
/qemu-kvm-1.2.0.tar.gz
|
||||
|
38
0201-spice-abort-on-invalid-streaming-cmdline-params.patch
Normal file
38
0201-spice-abort-on-invalid-streaming-cmdline-params.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From 46851363e2aed89fc535803c8a23f6bed9934312 Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Fergeau <cfergeau@redhat.com>
|
||||
Date: Mon, 13 Aug 2012 10:32:32 +0200
|
||||
Subject: [PATCH 201/215] spice: abort on invalid streaming cmdline params
|
||||
|
||||
When parsing its command line parameters, spice aborts when it
|
||||
finds unexpected values, except for the 'streaming-video' option.
|
||||
This happens because the parsing of the parameters for this option
|
||||
is done using the 'name2enum' helper, which does not error out
|
||||
on unknown values. Using the 'parse_name' helper makes sure we
|
||||
error out in this case. Looking at git history, the use of
|
||||
'name2enum' instead of 'parse_name' seems to have been an oversight,
|
||||
so let's change to that now.
|
||||
|
||||
Fixes rhbz#831708
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
ui/spice-core.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index 4fc48f8..bb4f585 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -344,7 +344,8 @@ static const char *stream_video_names[] = {
|
||||
[ SPICE_STREAM_VIDEO_FILTER ] = "filter",
|
||||
};
|
||||
#define parse_stream_video(_name) \
|
||||
- name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
|
||||
+ parse_name(_name, "stream video control", \
|
||||
+ stream_video_names, ARRAY_SIZE(stream_video_names))
|
||||
|
||||
static const char *compression_names[] = {
|
||||
[ SPICE_IMAGE_COMPRESS_OFF ] = "off",
|
||||
--
|
||||
1.7.12
|
||||
|
52
0202-spice-notify-spice-server-on-vm-start-stop.patch
Normal file
52
0202-spice-notify-spice-server-on-vm-start-stop.patch
Normal file
@ -0,0 +1,52 @@
|
||||
From 2d2ccb50223c16fbf08140b9dd59275657de2a61 Mon Sep 17 00:00:00 2001
|
||||
From: Yonit Halperin <yhalperi@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 11:51:55 +0300
|
||||
Subject: [PATCH 202/215] spice: notify spice server on vm start/stop
|
||||
|
||||
Spice server needs to know about the vm state in order to prevent
|
||||
attempts to write to devices when they are stopped, mainly during
|
||||
the non-live stage of migration.
|
||||
Instead, spice will take care of restoring this writes, on the migration
|
||||
target side, after migration completes.
|
||||
|
||||
Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
ui/spice-core.c | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index bb4f585..a515c94 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -546,6 +546,18 @@ static int add_channel(const char *name, const char *value, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void vm_change_state_handler(void *opaque, int running,
|
||||
+ RunState state)
|
||||
+{
|
||||
+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */
|
||||
+ if (running) {
|
||||
+ spice_server_vm_start(spice_server);
|
||||
+ } else {
|
||||
+ spice_server_vm_stop(spice_server);
|
||||
+ }
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
void qemu_spice_init(void)
|
||||
{
|
||||
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
|
||||
@@ -719,6 +731,8 @@ void qemu_spice_init(void)
|
||||
qemu_spice_input_init();
|
||||
qemu_spice_audio_init();
|
||||
|
||||
+ qemu_add_vm_change_state_handler(vm_change_state_handler, &spice_server);
|
||||
+
|
||||
g_free(x509_key_file);
|
||||
g_free(x509_cert_file);
|
||||
g_free(x509_cacert_file);
|
||||
--
|
||||
1.7.12
|
||||
|
170
0203-spice-notify-on-vm-state-change-only-via-spice_serve.patch
Normal file
170
0203-spice-notify-on-vm-state-change-only-via-spice_serve.patch
Normal file
@ -0,0 +1,170 @@
|
||||
From f7d481b35b63f2df58aaef5afcac5ca1e67ce233 Mon Sep 17 00:00:00 2001
|
||||
From: Yonit Halperin <yhalperi@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 11:51:56 +0300
|
||||
Subject: [PATCH 203/215] spice: notify on vm state change only via
|
||||
spice_server_vm_start/stop
|
||||
|
||||
QXLWorker->start/stop are deprecated since spice-server 0.11.2
|
||||
|
||||
Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/qxl.c | 7 ++++---
|
||||
ui/spice-core.c | 4 ++++
|
||||
ui/spice-display.c | 32 ++++++++++++++++++++++++++++++--
|
||||
ui/spice-display.h | 9 +++++++--
|
||||
4 files changed, 45 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index c2dd3b4..95bbc03 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -958,9 +958,10 @@ static void qxl_update_irq(PCIQXLDevice *d)
|
||||
static void qxl_check_state(PCIQXLDevice *d)
|
||||
{
|
||||
QXLRam *ram = d->ram;
|
||||
+ int spice_display_running = qemu_spice_display_is_running(&d->ssd);
|
||||
|
||||
- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
|
||||
- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
|
||||
+ assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
|
||||
+ assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
|
||||
}
|
||||
|
||||
static void qxl_reset_state(PCIQXLDevice *d)
|
||||
@@ -1538,7 +1539,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
||||
uint32_t old_pending;
|
||||
uint32_t le_events = cpu_to_le32(events);
|
||||
|
||||
- assert(d->ssd.running);
|
||||
+ 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) {
|
||||
return;
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index a515c94..1a7a773 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "migration.h"
|
||||
#include "monitor.h"
|
||||
#include "hw/hw.h"
|
||||
+#include "spice-display.h"
|
||||
|
||||
/* core bits */
|
||||
|
||||
@@ -551,9 +552,11 @@ static void vm_change_state_handler(void *opaque, int running,
|
||||
{
|
||||
#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */
|
||||
if (running) {
|
||||
+ qemu_spice_display_start();
|
||||
spice_server_vm_start(spice_server);
|
||||
} else {
|
||||
spice_server_vm_stop(spice_server);
|
||||
+ qemu_spice_display_stop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -755,6 +758,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin)
|
||||
spice_server = spice_server_new();
|
||||
spice_server_init(spice_server, &core_interface);
|
||||
}
|
||||
+
|
||||
return spice_server_add_interface(spice_server, sin);
|
||||
}
|
||||
|
||||
diff --git a/ui/spice-display.c b/ui/spice-display.c
|
||||
index 3e8f0b3..1c31418 100644
|
||||
--- a/ui/spice-display.c
|
||||
+++ b/ui/spice-display.c
|
||||
@@ -126,18 +126,44 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
|
||||
ssd->worker->wakeup(ssd->worker);
|
||||
}
|
||||
|
||||
-void qemu_spice_start(SimpleSpiceDisplay *ssd)
|
||||
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
|
||||
+static void qemu_spice_start(SimpleSpiceDisplay *ssd)
|
||||
{
|
||||
trace_qemu_spice_start(ssd->qxl.id);
|
||||
ssd->worker->start(ssd->worker);
|
||||
}
|
||||
|
||||
-void qemu_spice_stop(SimpleSpiceDisplay *ssd)
|
||||
+static void qemu_spice_stop(SimpleSpiceDisplay *ssd)
|
||||
{
|
||||
trace_qemu_spice_stop(ssd->qxl.id);
|
||||
ssd->worker->stop(ssd->worker);
|
||||
}
|
||||
|
||||
+#else
|
||||
+
|
||||
+static int spice_display_is_running;
|
||||
+
|
||||
+void qemu_spice_display_start(void)
|
||||
+{
|
||||
+ spice_display_is_running = true;
|
||||
+}
|
||||
+
|
||||
+void qemu_spice_display_stop(void)
|
||||
+{
|
||||
+ spice_display_is_running = false;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd)
|
||||
+{
|
||||
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
|
||||
+ return ssd->running;
|
||||
+#else
|
||||
+ return spice_display_is_running;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
|
||||
{
|
||||
SimpleSpiceUpdate *update;
|
||||
@@ -272,6 +298,7 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
|
||||
void qemu_spice_vm_change_state_handler(void *opaque, int running,
|
||||
RunState state)
|
||||
{
|
||||
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
|
||||
SimpleSpiceDisplay *ssd = opaque;
|
||||
|
||||
if (running) {
|
||||
@@ -281,6 +308,7 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running,
|
||||
qemu_spice_stop(ssd);
|
||||
ssd->running = false;
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
|
||||
diff --git a/ui/spice-display.h b/ui/spice-display.h
|
||||
index 12e50b6..672d65e 100644
|
||||
--- a/ui/spice-display.h
|
||||
+++ b/ui/spice-display.h
|
||||
@@ -82,7 +82,9 @@ struct SimpleSpiceDisplay {
|
||||
|
||||
QXLRect dirty;
|
||||
int notify;
|
||||
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
|
||||
int running;
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* All struct members below this comment can be accessed from
|
||||
@@ -129,5 +131,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
|
||||
void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
|
||||
uint32_t id, qxl_async_io async);
|
||||
void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
|
||||
-void qemu_spice_start(SimpleSpiceDisplay *ssd);
|
||||
-void qemu_spice_stop(SimpleSpiceDisplay *ssd);
|
||||
+#if SPICE_SERVER_VERSION >= 0x000b02 /* before 0.11.2 */
|
||||
+void qemu_spice_display_start(void);
|
||||
+void qemu_spice_display_stop(void);
|
||||
+#endif
|
||||
+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd);
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,90 @@
|
||||
From d8543fcc36b38c76a638d15ed95d8b5acf27d93a Mon Sep 17 00:00:00 2001
|
||||
From: Yonit Halperin <yhalperi@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 11:51:57 +0300
|
||||
Subject: [PATCH 204/215] spice migration: add QEVENT_SPICE_MIGRATE_COMPLETED
|
||||
|
||||
When migrating, libvirt queries the migration status, and upon migration
|
||||
completions, it closes the migration src. On the other hand, when
|
||||
migration is completed, spice transfers data from the src to destination
|
||||
via the client. This data is required for keeping the spice session
|
||||
after migration, without suffering from data loss and inconsistencies.
|
||||
In order to allow this data transfer, we add QEVENT for signaling
|
||||
libvirt that spice migration has completed, and libvirt needs to wait
|
||||
for this event before quitting the src process.
|
||||
|
||||
Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
monitor.c | 1 +
|
||||
monitor.h | 1 +
|
||||
ui/spice-core.c | 9 ++++++++-
|
||||
3 files changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/monitor.c b/monitor.c
|
||||
index c14698d..99eee98 100644
|
||||
--- a/monitor.c
|
||||
+++ b/monitor.c
|
||||
@@ -455,6 +455,7 @@ static const char *monitor_event_names[] = {
|
||||
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
|
||||
[QEVENT_WAKEUP] = "WAKEUP",
|
||||
[QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
|
||||
+ [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED",
|
||||
};
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
|
||||
|
||||
diff --git a/monitor.h b/monitor.h
|
||||
index 47d556b..5fc2983 100644
|
||||
--- a/monitor.h
|
||||
+++ b/monitor.h
|
||||
@@ -43,6 +43,7 @@ typedef enum MonitorEvent {
|
||||
QEVENT_SUSPEND_DISK,
|
||||
QEVENT_WAKEUP,
|
||||
QEVENT_BALLOON_CHANGE,
|
||||
+ QEVENT_SPICE_MIGRATE_COMPLETED,
|
||||
|
||||
/* Add to 'monitor_event_names' array in monitor.c when
|
||||
* defining new events here */
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index 1a7a773..851e869 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -285,6 +285,7 @@ typedef struct SpiceMigration {
|
||||
} SpiceMigration;
|
||||
|
||||
static void migrate_connect_complete_cb(SpiceMigrateInstance *sin);
|
||||
+static void migrate_end_complete_cb(SpiceMigrateInstance *sin);
|
||||
|
||||
static const SpiceMigrateInterface migrate_interface = {
|
||||
.base.type = SPICE_INTERFACE_MIGRATION,
|
||||
@@ -292,7 +293,7 @@ static const SpiceMigrateInterface migrate_interface = {
|
||||
.base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR,
|
||||
.base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR,
|
||||
.migrate_connect_complete = migrate_connect_complete_cb,
|
||||
- .migrate_end_complete = NULL,
|
||||
+ .migrate_end_complete = migrate_end_complete_cb,
|
||||
};
|
||||
|
||||
static SpiceMigration spice_migrate;
|
||||
@@ -305,6 +306,11 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin)
|
||||
}
|
||||
sm->connect_complete.cb = NULL;
|
||||
}
|
||||
+
|
||||
+static void migrate_end_complete_cb(SpiceMigrateInstance *sin)
|
||||
+{
|
||||
+ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL);
|
||||
+}
|
||||
#endif
|
||||
|
||||
/* config string parsing */
|
||||
@@ -489,6 +495,7 @@ static void migration_state_notifier(Notifier *notifier, void *data)
|
||||
} else if (migration_has_finished(s)) {
|
||||
#ifndef SPICE_INTERFACE_MIGRATION
|
||||
spice_server_migrate_switch(spice_server);
|
||||
+ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL);
|
||||
#else
|
||||
spice_server_migrate_end(spice_server, true);
|
||||
} else if (migration_has_failed(s)) {
|
||||
--
|
||||
1.7.12
|
||||
|
94
0205-spice-add-migrated-flag-to-spice-info.patch
Normal file
94
0205-spice-add-migrated-flag-to-spice-info.patch
Normal file
@ -0,0 +1,94 @@
|
||||
From ad7734d7a3cb4560dcc0bef2794adeddc793af75 Mon Sep 17 00:00:00 2001
|
||||
From: Yonit Halperin <yhalperi@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 11:51:58 +0300
|
||||
Subject: [PATCH 205/215] spice: add 'migrated' flag to spice info
|
||||
|
||||
The flag is 'true' when spice migration has completed on the src side.
|
||||
It is needed for a case where libvirt dies before migration completes
|
||||
and it misses the event QEVENT_SPICE_MIGRATE_COMPLETED.
|
||||
When libvirt is restored and queries the migration status, it also needs
|
||||
to query spice and check if its migration has completed.
|
||||
|
||||
Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hmp.c | 2 ++
|
||||
qapi-schema.json | 5 ++++-
|
||||
ui/spice-core.c | 4 ++++
|
||||
3 files changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hmp.c b/hmp.c
|
||||
index 81c8acb..ec4274b 100644
|
||||
--- a/hmp.c
|
||||
+++ b/hmp.c
|
||||
@@ -413,6 +413,8 @@ void hmp_info_spice(Monitor *mon)
|
||||
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
||||
info->host, info->tls_port);
|
||||
}
|
||||
+ monitor_printf(mon, " migrated: %s\n",
|
||||
+ info->migrated ? "true" : "false");
|
||||
monitor_printf(mon, " auth: %s\n", info->auth);
|
||||
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
||||
monitor_printf(mon, " mouse-mode: %s\n",
|
||||
diff --git a/qapi-schema.json b/qapi-schema.json
|
||||
index bd8ad74..8ddde12 100644
|
||||
--- a/qapi-schema.json
|
||||
+++ b/qapi-schema.json
|
||||
@@ -808,6 +808,9 @@
|
||||
#
|
||||
# @enabled: true if the SPICE server is enabled, false otherwise
|
||||
#
|
||||
+# @migrated: true if the last guest migration completed and spice
|
||||
+# migration had completed as well. false otherwise.
|
||||
+#
|
||||
# @host: #optional The hostname the SPICE server is bound to. This depends on
|
||||
# the name resolution on the host and may be an IP address.
|
||||
#
|
||||
@@ -833,7 +836,7 @@
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'SpiceInfo',
|
||||
- 'data': {'enabled': 'bool', '*host': 'str', '*port': 'int',
|
||||
+ 'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
|
||||
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
|
||||
'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
|
||||
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index 851e869..ab069c5 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -46,6 +46,7 @@ static Notifier migration_state;
|
||||
static const char *auth = "spice";
|
||||
static char *auth_passwd;
|
||||
static time_t auth_expires = TIME_MAX;
|
||||
+static int spice_migration_completed;
|
||||
int using_spice = 0;
|
||||
|
||||
static QemuThread me;
|
||||
@@ -310,6 +311,7 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin)
|
||||
static void migrate_end_complete_cb(SpiceMigrateInstance *sin)
|
||||
{
|
||||
monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL);
|
||||
+ spice_migration_completed = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -443,6 +445,7 @@ SpiceInfo *qmp_query_spice(Error **errp)
|
||||
}
|
||||
|
||||
info->enabled = true;
|
||||
+ info->migrated = spice_migration_completed;
|
||||
|
||||
addr = qemu_opt_get(opts, "addr");
|
||||
port = qemu_opt_get_number(opts, "port", 0);
|
||||
@@ -496,6 +499,7 @@ static void migration_state_notifier(Notifier *notifier, void *data)
|
||||
#ifndef SPICE_INTERFACE_MIGRATION
|
||||
spice_server_migrate_switch(spice_server);
|
||||
monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL);
|
||||
+ spice_migration_completed = true;
|
||||
#else
|
||||
spice_server_migrate_end(spice_server, true);
|
||||
} else if (migration_has_failed(s)) {
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,77 @@
|
||||
From 978a72a62c36e932a4b7ae18a5cf23d2d30e9755 Mon Sep 17 00:00:00 2001
|
||||
From: Yonit Halperin <yhalperi@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 11:51:59 +0300
|
||||
Subject: [PATCH 206/215] spice: adding seamless-migration option to the
|
||||
command line
|
||||
|
||||
The seamless-migration flag is required in order to identify
|
||||
whether libvirt supports the new QEVENT_SPICE_MIGRATE_COMPLETED or not
|
||||
(by default the flag is off).
|
||||
New libvirt versions that wait for QEVENT_SPICE_MIGRATE_COMPLETED should turn on this flag.
|
||||
When this flag is off, spice fallbacks to its old migration method, which
|
||||
can result in data loss.
|
||||
|
||||
Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
qemu-config.c | 3 +++
|
||||
qemu-options.hx | 3 +++
|
||||
ui/spice-core.c | 7 +++++++
|
||||
3 files changed, 13 insertions(+)
|
||||
|
||||
diff --git a/qemu-config.c b/qemu-config.c
|
||||
index 238390e..3eaee48 100644
|
||||
--- a/qemu-config.c
|
||||
+++ b/qemu-config.c
|
||||
@@ -541,6 +541,9 @@ QemuOptsList qemu_spice_opts = {
|
||||
},{
|
||||
.name = "playback-compression",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
+ }, {
|
||||
+ .name = "seamless-migration",
|
||||
+ .type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
diff --git a/qemu-options.hx b/qemu-options.hx
|
||||
index ea06324..dd7aa63 100644
|
||||
--- a/qemu-options.hx
|
||||
+++ b/qemu-options.hx
|
||||
@@ -920,6 +920,9 @@ Enable/disable passing mouse events via vdagent. Default is on.
|
||||
@item playback-compression=[on|off]
|
||||
Enable/disable audio stream compression (using celt 0.5.1). Default is on.
|
||||
|
||||
+@item seamless-migration=[on|off]
|
||||
+Enable/disable spice seamless migration. Default is off.
|
||||
+
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index ab069c5..ba0d0bd 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -585,6 +585,9 @@ void qemu_spice_init(void)
|
||||
int port, tls_port, len, addr_flags;
|
||||
spice_image_compression_t compression;
|
||||
spice_wan_compression_t wan_compr;
|
||||
+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */
|
||||
+ bool seamless_migration;
|
||||
+#endif
|
||||
|
||||
qemu_thread_get_self(&me);
|
||||
|
||||
@@ -728,6 +731,10 @@ void qemu_spice_init(void)
|
||||
spice_server_set_uuid(spice_server, qemu_uuid);
|
||||
#endif
|
||||
|
||||
+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */
|
||||
+ seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0);
|
||||
+ spice_server_set_seamless_migration(spice_server, seamless_migration);
|
||||
+#endif
|
||||
if (0 != spice_server_init(spice_server, &core_interface)) {
|
||||
error_report("failed to initialize spice server");
|
||||
exit(1);
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,47 @@
|
||||
From 54704702dbbb1d55f2aaecf5c837a583d9e209a5 Mon Sep 17 00:00:00 2001
|
||||
From: Yonit Halperin <yhalperi@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 13:54:20 +0300
|
||||
Subject: [PATCH 207/215] spice: increase the verbosity of spice section in
|
||||
"qemu --help"
|
||||
|
||||
Added all spice options to the help string. This can be used by libvirt
|
||||
to determine which spice related features are supported by qemu.
|
||||
|
||||
Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
qemu-options.hx | 18 +++++++++++++++++-
|
||||
1 file changed, 17 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/qemu-options.hx b/qemu-options.hx
|
||||
index dd7aa63..1af4fec 100644
|
||||
--- a/qemu-options.hx
|
||||
+++ b/qemu-options.hx
|
||||
@@ -838,7 +838,23 @@ Enable SDL.
|
||||
ETEXI
|
||||
|
||||
DEF("spice", HAS_ARG, QEMU_OPTION_spice,
|
||||
- "-spice <args> enable spice\n", QEMU_ARCH_ALL)
|
||||
+ "-spice [port=port][,tls-port=secured-port][,x509-dir=<dir>]\n"
|
||||
+ " [,x509-key-file=<file>][,x509-key-password=<file>]\n"
|
||||
+ " [,x509-cert-file=<file>][,x509-cacert-file=<file>]\n"
|
||||
+ " [,x509-dh-key-file=<file>][,addr=addr][,ipv4|ipv6]\n"
|
||||
+ " [,tls-ciphers=<list>]\n"
|
||||
+ " [,tls-channel=[main|display|cursor|inputs|record|playback]]\n"
|
||||
+ " [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n"
|
||||
+ " [,sasl][,password=<secret>][,disable-ticketing]\n"
|
||||
+ " [,image-compression=[auto_glz|auto_lz|quic|glz|lz|off]]\n"
|
||||
+ " [,jpeg-wan-compression=[auto|never|always]]\n"
|
||||
+ " [,zlib-glz-wan-compression=[auto|never|always]]\n"
|
||||
+ " [,streaming-video=[off|all|filter]][,disable-copy-paste]\n"
|
||||
+ " [,agent-mouse=[on|off]][,playback-compression=[on|off]]\n"
|
||||
+ " [,seamless-migration=[on|off]]\n"
|
||||
+ " enable spice\n"
|
||||
+ " at least one of {port, tls-port} is mandatory\n",
|
||||
+ QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -spice @var{option}[,@var{option}[,...]]
|
||||
@findex -spice
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,37 @@
|
||||
From c3236169b390617d13ede20ff0aed5d0bc1aba66 Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 13:51:31 +0300
|
||||
Subject: [PATCH 208/215] qxl/update_area_io: guest_bug on invalid parameters
|
||||
|
||||
Signed-off-by: Alon Levy <alevy@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/qxl.c | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index 95bbc03..baf9bb4 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -1386,6 +1386,18 @@ async_common:
|
||||
QXLCookie *cookie = NULL;
|
||||
QXLRect update = d->ram->update_area;
|
||||
|
||||
+ if (d->ram->update_surface > NUM_SURFACES) {
|
||||
+ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
|
||||
+ d->ram->update_surface);
|
||||
+ return;
|
||||
+ }
|
||||
+ if (update.left >= update.right || update.top >= update.bottom) {
|
||||
+ qxl_set_guest_bug(d,
|
||||
+ "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n",
|
||||
+ update.left, update.top, update.right, update.bottom);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (async == QXL_ASYNC) {
|
||||
cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
|
||||
QXL_IO_UPDATE_AREA_ASYNC);
|
||||
--
|
||||
1.7.12
|
||||
|
33
0209-qxl-disallow-unknown-revisions.patch
Normal file
33
0209-qxl-disallow-unknown-revisions.patch
Normal file
@ -0,0 +1,33 @@
|
||||
From 31052a357ad124c9ed17fbc39a0db5c8d6d0d9c5 Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 13:51:32 +0300
|
||||
Subject: [PATCH 209/215] qxl: disallow unknown revisions
|
||||
|
||||
Signed-off-by: Alon Levy <alevy@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/qxl.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index baf9bb4..d134a70 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -1798,10 +1798,13 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
io_size = 16;
|
||||
break;
|
||||
case 3: /* qxl-3 */
|
||||
- default:
|
||||
pci_device_rev = QXL_DEFAULT_REVISION;
|
||||
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
|
||||
break;
|
||||
+ default:
|
||||
+ error_report("Invalid revision %d for qxl device (max %d)",
|
||||
+ qxl->revision, QXL_DEFAULT_REVISION);
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
|
||||
--
|
||||
1.7.12
|
||||
|
321
0210-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch
Normal file
321
0210-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch
Normal file
@ -0,0 +1,321 @@
|
||||
From cc8b6a27e848cb88a4df98d48517c5b658d70efc Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Wed, 22 Aug 2012 11:16:25 +0300
|
||||
Subject: [PATCH 210/215] qxl: add QXL_IO_MONITORS_CONFIG_ASYNC
|
||||
|
||||
Revision bumped to 4 for new IO support, enabled for spice-server >=
|
||||
0.11.1. New io enabled if revision is 4. Revision can be set to 4.
|
||||
|
||||
[ kraxel: 3 continues to be the default revision. Once we have a new
|
||||
stable spice-server release and the qemu patches to enable
|
||||
the new bits merged we'll go flip the switch and make rev4
|
||||
the default ]
|
||||
|
||||
This io calls the corresponding new spice api
|
||||
spice_qxl_monitors_config_async to let spice-server read a new guest set
|
||||
monitors config and notify the client.
|
||||
|
||||
On migration reissue spice_qxl_monitors_config_async.
|
||||
|
||||
RHBZ: 770842
|
||||
|
||||
Signed-off-by: Alon Levy <alevy@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
|
||||
fixup
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
configure | 7 ++++
|
||||
hw/qxl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
hw/qxl.h | 7 ++++
|
||||
trace-events | 1 +
|
||||
ui/spice-display.h | 1 +
|
||||
5 files changed, 109 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/configure b/configure
|
||||
index 9fc4fb5..c57d1c1 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -2711,6 +2711,9 @@ EOF
|
||||
spice="yes"
|
||||
libs_softmmu="$libs_softmmu $spice_libs"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
|
||||
+ if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then
|
||||
+ spice_qxl_io_monitors_config_async="yes"
|
||||
+ fi
|
||||
else
|
||||
if test "$spice" = "yes" ; then
|
||||
feature_not_found "spice"
|
||||
@@ -3448,6 +3451,10 @@ if test "$spice" = "yes" ; then
|
||||
echo "CONFIG_SPICE=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
+if test "$spice_qxl_io_monitors_config_async" = "yes" ; then
|
||||
+ echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=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 d134a70..adf17fd 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -27,6 +27,11 @@
|
||||
|
||||
#include "qxl.h"
|
||||
|
||||
+#ifndef CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC
|
||||
+/* spice-protocol is too old, add missing definitions */
|
||||
+#define QXL_IO_MONITORS_CONFIG_ASYNC (QXL_IO_FLUSH_RELEASE + 1)
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
|
||||
* such can be changed by the guest, so to avoid a guest trigerrable
|
||||
@@ -249,6 +254,39 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
|
||||
}
|
||||
}
|
||||
|
||||
+static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
|
||||
+{
|
||||
+ trace_qxl_spice_monitors_config(qxl->id);
|
||||
+/* 0x000b01 == 0.11.1 */
|
||||
+#if SPICE_SERVER_VERSION >= 0x000b01 && \
|
||||
+ defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC)
|
||||
+ if (replay) {
|
||||
+ /*
|
||||
+ * don't use QXL_COOKIE_TYPE_IO:
|
||||
+ * - we are not running yet (post_load), we will assert
|
||||
+ * in send_events
|
||||
+ * - this is not a guest io, but a reply, so async_io isn't set.
|
||||
+ */
|
||||
+ spice_qxl_monitors_config_async(&qxl->ssd.qxl,
|
||||
+ qxl->guest_monitors_config,
|
||||
+ MEMSLOT_GROUP_GUEST,
|
||||
+ (uintptr_t)qxl_cookie_new(
|
||||
+ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
|
||||
+ 0));
|
||||
+ } else {
|
||||
+ qxl->guest_monitors_config = qxl->ram->monitors_config;
|
||||
+ spice_qxl_monitors_config_async(&qxl->ssd.qxl,
|
||||
+ qxl->ram->monitors_config,
|
||||
+ MEMSLOT_GROUP_GUEST,
|
||||
+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
|
||||
+ QXL_IO_MONITORS_CONFIG_ASYNC));
|
||||
+ }
|
||||
+#else
|
||||
+ fprintf(stderr, "qxl: too old spice-protocol/spice-server for "
|
||||
+ "QXL_IO_MONITORS_CONFIG_ASYNC\n");
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
|
||||
{
|
||||
trace_qxl_spice_reset_image_cache(qxl->id);
|
||||
@@ -538,6 +576,7 @@ static const char *io_port_to_string(uint32_t io_port)
|
||||
= "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
|
||||
[QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC",
|
||||
[QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE",
|
||||
+ [QXL_IO_MONITORS_CONFIG_ASYNC] = "QXL_IO_MONITORS_CONFIG_ASYNC",
|
||||
};
|
||||
return io_port_to_string[io_port];
|
||||
}
|
||||
@@ -819,6 +858,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
|
||||
case QXL_IO_DESTROY_PRIMARY_ASYNC:
|
||||
case QXL_IO_UPDATE_AREA_ASYNC:
|
||||
case QXL_IO_FLUSH_SURFACES_ASYNC:
|
||||
+ case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||
break;
|
||||
case QXL_IO_CREATE_PRIMARY_ASYNC:
|
||||
qxl_create_guest_primary_complete(qxl);
|
||||
@@ -894,6 +934,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
|
||||
case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
|
||||
qxl_render_update_area_done(qxl, cookie);
|
||||
break;
|
||||
+ case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
|
||||
+ break;
|
||||
default:
|
||||
fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
|
||||
__func__, cookie->type);
|
||||
@@ -1315,6 +1357,13 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (d->revision <= QXL_REVISION_STABLE_V10 &&
|
||||
+ io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) {
|
||||
+ qxl_set_guest_bug(d, "unsupported io %d for revision %d\n",
|
||||
+ io_port, d->revision);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
switch (io_port) {
|
||||
case QXL_IO_RESET:
|
||||
case QXL_IO_SET_MODE:
|
||||
@@ -1334,7 +1383,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
||||
io_port, io_port_to_string(io_port));
|
||||
/* be nice to buggy guest drivers */
|
||||
if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
|
||||
- io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
|
||||
+ io_port < QXL_IO_RANGE_SIZE) {
|
||||
qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
|
||||
}
|
||||
return;
|
||||
@@ -1362,6 +1411,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
||||
io_port = QXL_IO_DESTROY_ALL_SURFACES;
|
||||
goto async_common;
|
||||
case QXL_IO_FLUSH_SURFACES_ASYNC:
|
||||
+ case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||
async_common:
|
||||
async = QXL_ASYNC;
|
||||
qemu_mutex_lock(&d->async_lock);
|
||||
@@ -1503,6 +1553,9 @@ async_common:
|
||||
d->mode = QXL_MODE_UNDEFINED;
|
||||
qxl_spice_destroy_surfaces(d, async);
|
||||
break;
|
||||
+ case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||
+ qxl_spice_monitors_config_async(d, 0);
|
||||
+ break;
|
||||
default:
|
||||
qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
|
||||
}
|
||||
@@ -1798,9 +1851,17 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
io_size = 16;
|
||||
break;
|
||||
case 3: /* qxl-3 */
|
||||
- pci_device_rev = QXL_DEFAULT_REVISION;
|
||||
+ pci_device_rev = QXL_REVISION_STABLE_V10;
|
||||
+ io_size = 32; /* PCI region size must be pow2 */
|
||||
+ break;
|
||||
+/* 0x000b01 == 0.11.1 */
|
||||
+#if SPICE_SERVER_VERSION >= 0x000b01 && \
|
||||
+ defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC)
|
||||
+ case 4: /* qxl-4 */
|
||||
+ pci_device_rev = QXL_REVISION_STABLE_V12;
|
||||
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
|
||||
break;
|
||||
+#endif
|
||||
default:
|
||||
error_report("Invalid revision %d for qxl device (max %d)",
|
||||
qxl->revision, QXL_DEFAULT_REVISION);
|
||||
@@ -1999,7 +2060,9 @@ static int qxl_post_load(void *opaque, int version)
|
||||
}
|
||||
qxl_spice_loadvm_commands(d, cmds, out);
|
||||
g_free(cmds);
|
||||
-
|
||||
+ if (d->guest_monitors_config) {
|
||||
+ qxl_spice_monitors_config_async(d, 1);
|
||||
+ }
|
||||
break;
|
||||
case QXL_MODE_COMPAT:
|
||||
/* note: no need to call qxl_create_memslots, qxl_set_mode
|
||||
@@ -2012,6 +2075,14 @@ static int qxl_post_load(void *opaque, int version)
|
||||
|
||||
#define QXL_SAVE_VERSION 21
|
||||
|
||||
+static bool qxl_monitors_config_needed(void *opaque)
|
||||
+{
|
||||
+ PCIQXLDevice *qxl = opaque;
|
||||
+
|
||||
+ return qxl->guest_monitors_config != 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static VMStateDescription qxl_memslot = {
|
||||
.name = "qxl-memslot",
|
||||
.version_id = QXL_SAVE_VERSION,
|
||||
@@ -2042,6 +2113,16 @@ static VMStateDescription qxl_surface = {
|
||||
}
|
||||
};
|
||||
|
||||
+static VMStateDescription qxl_vmstate_monitors_config = {
|
||||
+ .name = "qxl/monitors-config",
|
||||
+ .version_id = 1,
|
||||
+ .minimum_version_id = 1,
|
||||
+ .fields = (VMStateField[]) {
|
||||
+ VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
|
||||
+ VMSTATE_END_OF_LIST()
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static VMStateDescription qxl_vmstate = {
|
||||
.name = "qxl",
|
||||
.version_id = QXL_SAVE_VERSION,
|
||||
@@ -2049,7 +2130,7 @@ static VMStateDescription qxl_vmstate = {
|
||||
.pre_save = qxl_pre_save,
|
||||
.pre_load = qxl_pre_load,
|
||||
.post_load = qxl_post_load,
|
||||
- .fields = (VMStateField []) {
|
||||
+ .fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
|
||||
VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
|
||||
VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
|
||||
@@ -2068,6 +2149,14 @@ static VMStateDescription qxl_vmstate = {
|
||||
VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
+ .subsections = (VMStateSubsection[]) {
|
||||
+ {
|
||||
+ .vmsd = &qxl_vmstate_monitors_config,
|
||||
+ .needed = qxl_monitors_config_needed,
|
||||
+ }, {
|
||||
+ /* empty */
|
||||
+ }
|
||||
+ }
|
||||
};
|
||||
|
||||
static Property qxl_properties[] = {
|
||||
diff --git a/hw/qxl.h b/hw/qxl.h
|
||||
index 172baf6..9cfedb7 100644
|
||||
--- a/hw/qxl.h
|
||||
+++ b/hw/qxl.h
|
||||
@@ -71,6 +71,8 @@ typedef struct PCIQXLDevice {
|
||||
} guest_surfaces;
|
||||
QXLPHYSICAL guest_cursor;
|
||||
|
||||
+ QXLPHYSICAL guest_monitors_config;
|
||||
+
|
||||
QemuMutex track_lock;
|
||||
|
||||
/* thread signaling */
|
||||
@@ -128,7 +130,12 @@ typedef struct PCIQXLDevice {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
+#if 0
|
||||
+/* spice-server 0.12 is still in development */
|
||||
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
|
||||
+#else
|
||||
#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
|
||||
+#endif
|
||||
|
||||
/* qxl.c */
|
||||
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
|
||||
diff --git a/trace-events b/trace-events
|
||||
index 0de70d9..a58b0b7 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -967,6 +967,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_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"
|
||||
diff --git a/ui/spice-display.h b/ui/spice-display.h
|
||||
index 672d65e..bcff114 100644
|
||||
--- a/ui/spice-display.h
|
||||
+++ b/ui/spice-display.h
|
||||
@@ -51,6 +51,7 @@ typedef enum qxl_async_io {
|
||||
enum {
|
||||
QXL_COOKIE_TYPE_IO,
|
||||
QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
|
||||
+ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
|
||||
};
|
||||
|
||||
typedef struct QXLCookie {
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,37 @@
|
||||
From 1d2790682dfac06c2358ac99f5e0bad6a065702d Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Wed, 22 Aug 2012 11:16:26 +0300
|
||||
Subject: [PATCH 211/215] configure: print spice-protocol and spice-server
|
||||
versions
|
||||
|
||||
Signed-off-by: Alon Levy <alevy@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
configure | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/configure b/configure
|
||||
index c57d1c1..25c406f 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -2711,6 +2711,8 @@ EOF
|
||||
spice="yes"
|
||||
libs_softmmu="$libs_softmmu $spice_libs"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
|
||||
+ spice_protocol_version=$($pkg_config --modversion spice-protocol)
|
||||
+ spice_server_version=$($pkg_config --modversion spice-server)
|
||||
if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then
|
||||
spice_qxl_io_monitors_config_async="yes"
|
||||
fi
|
||||
@@ -3169,7 +3171,7 @@ echo "libcap-ng support $cap_ng"
|
||||
echo "vhost-net support $vhost_net"
|
||||
echo "Trace backend $trace_backend"
|
||||
echo "Trace output file $trace_file-<pid>"
|
||||
-echo "spice support $spice"
|
||||
+echo "spice support $spice ($spice_protocol_version/$spice_server_version)"
|
||||
echo "rbd support $rbd"
|
||||
echo "xfsctl support $xfs"
|
||||
echo "nss used $smartcard_nss"
|
||||
--
|
||||
1.7.12
|
||||
|
201
0212-spice-make-number-of-surfaces-runtime-configurable.patch
Normal file
201
0212-spice-make-number-of-surfaces-runtime-configurable.patch
Normal file
@ -0,0 +1,201 @@
|
||||
From 72e437d9b775cb92f93c3acd0109239f1bb3e6e2 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 4 Sep 2012 11:39:41 +0200
|
||||
Subject: [PATCH 212/215] spice: make number of surfaces runtime-configurable.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/qxl.c | 31 +++++++++++++++++--------------
|
||||
hw/qxl.h | 3 +--
|
||||
ui/spice-display.c | 5 ++++-
|
||||
ui/spice-display.h | 3 +--
|
||||
4 files changed, 23 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index adf17fd..8725f67 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -236,7 +236,8 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
|
||||
{
|
||||
trace_qxl_spice_destroy_surfaces_complete(qxl->id);
|
||||
qemu_mutex_lock(&qxl->track_lock);
|
||||
- memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
|
||||
+ memset(qxl->guest_surfaces.cmds, 0,
|
||||
+ sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces);
|
||||
qxl->guest_surfaces.count = 0;
|
||||
qemu_mutex_unlock(&qxl->track_lock);
|
||||
}
|
||||
@@ -345,7 +346,7 @@ static void init_qxl_rom(PCIQXLDevice *d)
|
||||
rom->slot_id_bits = MEMSLOT_SLOT_BITS;
|
||||
rom->slots_start = 1;
|
||||
rom->slots_end = NUM_MEMSLOTS - 1;
|
||||
- rom->n_surfaces = cpu_to_le32(NUM_SURFACES);
|
||||
+ rom->n_surfaces = cpu_to_le32(d->ssd.num_surfaces);
|
||||
|
||||
for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) {
|
||||
fb = qxl_modes[i].y_res * qxl_modes[i].stride;
|
||||
@@ -449,9 +450,9 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
|
||||
}
|
||||
uint32_t id = le32_to_cpu(cmd->surface_id);
|
||||
|
||||
- if (id >= NUM_SURFACES) {
|
||||
+ if (id >= qxl->ssd.num_surfaces) {
|
||||
qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id,
|
||||
- NUM_SURFACES);
|
||||
+ qxl->ssd.num_surfaces);
|
||||
return 1;
|
||||
}
|
||||
qemu_mutex_lock(&qxl->track_lock);
|
||||
@@ -527,7 +528,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
|
||||
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
|
||||
info->internal_groupslot_id = 0;
|
||||
info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
|
||||
- info->n_surfaces = NUM_SURFACES;
|
||||
+ info->n_surfaces = qxl->ssd.num_surfaces;
|
||||
}
|
||||
|
||||
static const char *qxl_mode_to_string(int mode)
|
||||
@@ -1436,7 +1437,7 @@ async_common:
|
||||
QXLCookie *cookie = NULL;
|
||||
QXLRect update = d->ram->update_area;
|
||||
|
||||
- if (d->ram->update_surface > NUM_SURFACES) {
|
||||
+ if (d->ram->update_surface > d->ssd.num_surfaces) {
|
||||
qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
|
||||
d->ram->update_surface);
|
||||
return;
|
||||
@@ -1529,7 +1530,7 @@ async_common:
|
||||
}
|
||||
break;
|
||||
case QXL_IO_DESTROY_SURFACE_WAIT:
|
||||
- if (val >= NUM_SURFACES) {
|
||||
+ if (val >= d->ssd.num_surfaces) {
|
||||
qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
|
||||
"%" PRIu64 " >= NUM_SURFACES", async, val);
|
||||
goto cancel_async;
|
||||
@@ -1707,7 +1708,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
|
||||
vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
|
||||
|
||||
/* dirty the off-screen surfaces */
|
||||
- for (i = 0; i < NUM_SURFACES; i++) {
|
||||
+ for (i = 0; i < qxl->ssd.num_surfaces; i++) {
|
||||
QXLSurfaceCmd *cmd;
|
||||
intptr_t surface_offset;
|
||||
int surface_size;
|
||||
@@ -1835,7 +1836,6 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
qxl->mode = QXL_MODE_UNDEFINED;
|
||||
qxl->generation = 1;
|
||||
qxl->num_memslots = NUM_MEMSLOTS;
|
||||
- qxl->num_surfaces = NUM_SURFACES;
|
||||
qemu_mutex_init(&qxl->track_lock);
|
||||
qemu_mutex_init(&qxl->async_lock);
|
||||
qxl->current_async = QXL_UNDEFINED_IO;
|
||||
@@ -1877,6 +1877,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
init_qxl_rom(qxl);
|
||||
init_qxl_ram(qxl);
|
||||
|
||||
+ qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
|
||||
memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size);
|
||||
vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
|
||||
memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar,
|
||||
@@ -2042,8 +2043,8 @@ static int qxl_post_load(void *opaque, int version)
|
||||
qxl_create_guest_primary(d, 1, QXL_SYNC);
|
||||
|
||||
/* replay surface-create and cursor-set commands */
|
||||
- cmds = g_malloc0(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
|
||||
- for (in = 0, out = 0; in < NUM_SURFACES; in++) {
|
||||
+ cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1));
|
||||
+ for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) {
|
||||
if (d->guest_surfaces.cmds[in] == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -2143,9 +2144,10 @@ static VMStateDescription qxl_vmstate = {
|
||||
qxl_memslot, struct guest_slots),
|
||||
VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
|
||||
qxl_surface, QXLSurfaceCreate),
|
||||
- VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice),
|
||||
- VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0,
|
||||
- vmstate_info_uint64, uint64_t),
|
||||
+ VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice),
|
||||
+ VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice,
|
||||
+ ssd.num_surfaces, 0,
|
||||
+ vmstate_info_uint64, uint64_t),
|
||||
VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
@@ -2173,6 +2175,7 @@ static Property qxl_properties[] = {
|
||||
DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
|
||||
DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
|
||||
DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16),
|
||||
+ DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
diff --git a/hw/qxl.h b/hw/qxl.h
|
||||
index 9cfedb7..5553824 100644
|
||||
--- a/hw/qxl.h
|
||||
+++ b/hw/qxl.h
|
||||
@@ -40,7 +40,6 @@ typedef struct PCIQXLDevice {
|
||||
uint32_t revision;
|
||||
|
||||
int32_t num_memslots;
|
||||
- int32_t num_surfaces;
|
||||
|
||||
uint32_t current_async;
|
||||
QemuMutex async_lock;
|
||||
@@ -65,7 +64,7 @@ typedef struct PCIQXLDevice {
|
||||
} guest_primary;
|
||||
|
||||
struct surfaces {
|
||||
- QXLPHYSICAL cmds[NUM_SURFACES];
|
||||
+ QXLPHYSICAL *cmds;
|
||||
uint32_t count;
|
||||
uint32_t max;
|
||||
} guest_surfaces;
|
||||
diff --git a/ui/spice-display.c b/ui/spice-display.c
|
||||
index 1c31418..99bc665 100644
|
||||
--- a/ui/spice-display.c
|
||||
+++ b/ui/spice-display.c
|
||||
@@ -317,6 +317,9 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
|
||||
qemu_mutex_init(&ssd->lock);
|
||||
ssd->mouse_x = -1;
|
||||
ssd->mouse_y = -1;
|
||||
+ if (ssd->num_surfaces == 0) {
|
||||
+ ssd->num_surfaces = 1024;
|
||||
+ }
|
||||
ssd->bufsize = (16 * 1024 * 1024);
|
||||
ssd->buf = g_malloc(ssd->bufsize);
|
||||
}
|
||||
@@ -427,7 +430,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
|
||||
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
|
||||
info->internal_groupslot_id = 0;
|
||||
info->qxl_ram_size = ssd->bufsize;
|
||||
- info->n_surfaces = NUM_SURFACES;
|
||||
+ info->n_surfaces = ssd->num_surfaces;
|
||||
}
|
||||
|
||||
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
||||
diff --git a/ui/spice-display.h b/ui/spice-display.h
|
||||
index bcff114..512ab78 100644
|
||||
--- a/ui/spice-display.h
|
||||
+++ b/ui/spice-display.h
|
||||
@@ -32,8 +32,6 @@
|
||||
#define MEMSLOT_GROUP_GUEST 1
|
||||
#define NUM_MEMSLOTS_GROUPS 2
|
||||
|
||||
-#define NUM_SURFACES 1024
|
||||
-
|
||||
/*
|
||||
* Internal enum to differenciate between options for
|
||||
* io calls that have a sync (old) version and an _async (new)
|
||||
@@ -80,6 +78,7 @@ struct SimpleSpiceDisplay {
|
||||
QXLInstance qxl;
|
||||
uint32_t unique;
|
||||
QemuPfConv *conv;
|
||||
+ int32_t num_surfaces;
|
||||
|
||||
QXLRect dirty;
|
||||
int notify;
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,65 @@
|
||||
From 44eab2c48c8b090fff8b7ded39b40dae6c6ce003 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?S=C3=B8ren=20Sandmann=20Pedersen?= <ssp@redhat.com>
|
||||
Date: Tue, 4 Sep 2012 10:14:48 -0400
|
||||
Subject: [PATCH 213/215] qxl: Add set_client_capabilities() interface to
|
||||
QXLInterface
|
||||
|
||||
This new interface lets spice server inform the guest whether
|
||||
|
||||
(a) a client is connected
|
||||
(b) what capabilities the client has
|
||||
|
||||
There is a fixed number (464) of bits reserved for capabilities, and
|
||||
when the capabilities bits change, the QXL_INTERRUPT_CLIENT interrupt
|
||||
is generated.
|
||||
|
||||
Signed-off-by: Soren Sandmann <ssp@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/qxl.c | 23 +++++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index 8725f67..2aa5848 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -944,6 +944,26 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
|
||||
}
|
||||
}
|
||||
|
||||
+#if SPICE_SERVER_VERSION >= 0x000b04
|
||||
+
|
||||
+/* called from spice server thread context only */
|
||||
+static void interface_set_client_capabilities(QXLInstance *sin,
|
||||
+ uint8_t client_present,
|
||||
+ uint8_t caps[58])
|
||||
+{
|
||||
+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
|
||||
+
|
||||
+ qxl->shadow_rom.client_present = client_present;
|
||||
+ memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps));
|
||||
+ qxl->rom->client_present = client_present;
|
||||
+ memcpy(qxl->rom->client_capabilities, caps, sizeof(caps));
|
||||
+ qxl_rom_set_dirty(qxl);
|
||||
+
|
||||
+ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
static const QXLInterface qxl_interface = {
|
||||
.base.type = SPICE_INTERFACE_QXL,
|
||||
.base.description = "qxl gpu",
|
||||
@@ -965,6 +985,9 @@ static const QXLInterface qxl_interface = {
|
||||
.flush_resources = interface_flush_resources,
|
||||
.async_complete = interface_async_complete,
|
||||
.update_area_complete = interface_update_area_complete,
|
||||
+#if SPICE_SERVER_VERSION >= 0x000b04
|
||||
+ .set_client_capabilities = interface_set_client_capabilities,
|
||||
+#endif
|
||||
};
|
||||
|
||||
static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
||||
--
|
||||
1.7.12
|
||||
|
32
0214-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch
Normal file
32
0214-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 666f88952fe1bcf84ba857f417a5d25f86bbf38b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?S=C3=B8ren=20Sandmann=20Pedersen?= <ssp@redhat.com>
|
||||
Date: Tue, 4 Sep 2012 10:14:49 -0400
|
||||
Subject: [PATCH 214/215] Remove #ifdef QXL_COMMAND_FLAG_COMPAT_16BPP
|
||||
|
||||
We require spice >= 0.8 now, so this flag is always present.
|
||||
|
||||
Signed-off-by: Soren Sandmann <ssp@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/qxl.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index 2aa5848..b726c19 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -1359,11 +1359,9 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
|
||||
|
||||
d->mode = QXL_MODE_COMPAT;
|
||||
d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
|
||||
-#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */
|
||||
if (mode->bits == 16) {
|
||||
d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
|
||||
}
|
||||
-#endif
|
||||
d->shadow_rom.mode = cpu_to_le32(modenr);
|
||||
d->rom->mode = cpu_to_le32(modenr);
|
||||
qxl_rom_set_dirty(d);
|
||||
--
|
||||
1.7.12
|
||||
|
41
0215-qxl-dont-update-invalid-area.patch
Normal file
41
0215-qxl-dont-update-invalid-area.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From 6f1652c4412ab60c7f456100143c519d124a895c Mon Sep 17 00:00:00 2001
|
||||
From: Dunrong Huang <riegamaths@gmail.com>
|
||||
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 <riegamaths@gmail.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,56 @@
|
||||
From d69c3f589874de55e2eae03110a0c696485b8fa7 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Fri, 17 Aug 2012 11:39:16 +0200
|
||||
Subject: [PATCH 301/366] usb: controllers do not need to check for babble
|
||||
themselves
|
||||
|
||||
If an (emulated) usb-device tries to write more data to a packet then
|
||||
its iov len, this will trigger an assert in usb_packet_copy(), and if
|
||||
a driver somehow circumvents that check and writes more data to the
|
||||
iov then there is space, we have a much bigger problem then not correctly
|
||||
reporting babble to the guest.
|
||||
|
||||
In practice babble will only happen with (real) redirected devices, and there
|
||||
both the usb-host os and the qemu usb-device code already check for it.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 4 ----
|
||||
hw/usb/hcd-uhci.c | 5 -----
|
||||
2 files changed, 9 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 017342b..9523247 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -1481,10 +1481,6 @@ static void ehci_execute_complete(EHCIQueue *q)
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
- } else if ((p->usb_status > p->tbytes) && (p->pid == USB_TOKEN_IN)) {
|
||||
- p->usb_status = USB_RET_BABBLE;
|
||||
- q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
|
||||
- ehci_raise_irq(q->ehci, USBSTS_ERRINT);
|
||||
} else {
|
||||
// TODO check 4.12 for splits
|
||||
|
||||
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
|
||||
index b0db921..c7c8786 100644
|
||||
--- a/hw/usb/hcd-uhci.c
|
||||
+++ b/hw/usb/hcd-uhci.c
|
||||
@@ -729,11 +729,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
|
||||
*int_mask |= 0x01;
|
||||
|
||||
if (pid == USB_TOKEN_IN) {
|
||||
- if (len > max_len) {
|
||||
- ret = USB_RET_BABBLE;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
|
||||
*int_mask |= 0x02;
|
||||
/* short packet: do not update QH */
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,35 @@
|
||||
From ae5b888748b713d018ca7b339262b32bf88ec1be Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 12:33:44 +0200
|
||||
Subject: [PATCH 302/366] usb-core: Don't set packet state to complete on a
|
||||
nak
|
||||
|
||||
This way the hcd can re-use the same packet to retry without needing
|
||||
to re-init it.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/core.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/core.c b/hw/usb/core.c
|
||||
index 2da38e7..be6d936 100644
|
||||
--- a/hw/usb/core.c
|
||||
+++ b/hw/usb/core.c
|
||||
@@ -399,8 +399,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
|
||||
* otherwise packets can complete out of order!
|
||||
*/
|
||||
assert(!p->ep->pipeline);
|
||||
- p->result = ret;
|
||||
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
+ if (ret != USB_RET_NAK) {
|
||||
+ p->result = ret;
|
||||
+ usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
+ }
|
||||
}
|
||||
} else {
|
||||
ret = USB_RET_ASYNC;
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,52 @@
|
||||
From d42de93ca42a6d3b5101ec3db474f52a87a07a63 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 09:43:18 +0200
|
||||
Subject: [PATCH 303/366] usb-core: Add a usb_ep_find_packet_by_id() helper
|
||||
function
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb.h | 2 ++
|
||||
hw/usb/core.c | 15 +++++++++++++++
|
||||
2 files changed, 17 insertions(+)
|
||||
|
||||
diff --git a/hw/usb.h b/hw/usb.h
|
||||
index b8fceec..684e3f4 100644
|
||||
--- a/hw/usb.h
|
||||
+++ b/hw/usb.h
|
||||
@@ -377,6 +377,8 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
|
||||
uint16_t raw);
|
||||
int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
|
||||
void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled);
|
||||
+USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
|
||||
+ uint64_t id);
|
||||
|
||||
void usb_attach(USBPort *port);
|
||||
void usb_detach(USBPort *port);
|
||||
diff --git a/hw/usb/core.c b/hw/usb/core.c
|
||||
index be6d936..fe431d0 100644
|
||||
--- a/hw/usb/core.c
|
||||
+++ b/hw/usb/core.c
|
||||
@@ -726,3 +726,18 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled)
|
||||
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||
uep->pipeline = enabled;
|
||||
}
|
||||
+
|
||||
+USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
|
||||
+ uint64_t id)
|
||||
+{
|
||||
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||
+ USBPacket *p;
|
||||
+
|
||||
+ while ((p = QTAILQ_FIRST(&uep->queue)) != NULL) {
|
||||
+ if (p->id == id) {
|
||||
+ return p;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,32 @@
|
||||
From d0c16c3cd8dc1f2dc5ca6dae0d09e5f066332531 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 12:48:49 +0200
|
||||
Subject: [PATCH 304/366] usb-core: Allow the first packet of a pipelined ep
|
||||
to complete immediately
|
||||
|
||||
This can happen with usb-redir live-migration when the packet gets re-queued
|
||||
after the migration and the original queuing from the migration source side
|
||||
has already finished.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/core.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/core.c b/hw/usb/core.c
|
||||
index fe431d0..b9f1f7a 100644
|
||||
--- a/hw/usb/core.c
|
||||
+++ b/hw/usb/core.c
|
||||
@@ -398,7 +398,7 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
|
||||
* When pipelining is enabled usb-devices must always return async,
|
||||
* otherwise packets can complete out of order!
|
||||
*/
|
||||
- assert(!p->ep->pipeline);
|
||||
+ assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue));
|
||||
if (ret != USB_RET_NAK) {
|
||||
p->result = ret;
|
||||
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
--
|
||||
1.7.12
|
||||
|
121
0305-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch
Normal file
121
0305-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch
Normal file
@ -0,0 +1,121 @@
|
||||
From eccc0da01324939a52a74c763ade93e4a38d7328 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Wed, 29 Aug 2012 10:12:52 +0200
|
||||
Subject: [PATCH 305/366] Revert "ehci: don't flush cache on doorbell rings."
|
||||
|
||||
This reverts commit 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0, which got
|
||||
added to fix an issue where the real, underlying cause was not stopping
|
||||
the ep queue on an error.
|
||||
|
||||
Now that the underlying cause is fixed by the "usb: Halt ep queue and
|
||||
cancel pending packets on a packet error" patch, the "don't flush" fix
|
||||
is no longer needed.
|
||||
|
||||
Not only is it not needed, it causes us to see cancellations (unlinks)
|
||||
done by the Linux EHCI driver too late, which in combination with the new
|
||||
usb-core packet-id generation where qtd addresses are used as ids, causes
|
||||
duplicate ids for in flight packets.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 35 ++++++-----------------------------
|
||||
1 file changed, 6 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 9523247..e7c36f4 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -365,7 +365,6 @@ struct EHCIQueue {
|
||||
uint32_t seen;
|
||||
uint64_t ts;
|
||||
int async;
|
||||
- int revalidate;
|
||||
|
||||
/* cached data from guest - needs to be flushed
|
||||
* when guest removes an entry (doorbell, handshake sequence)
|
||||
@@ -805,18 +804,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static void ehci_queues_tag_unused_async(EHCIState *ehci)
|
||||
-{
|
||||
- EHCIQueue *q;
|
||||
-
|
||||
- QTAILQ_FOREACH(q, &ehci->aqueues, next) {
|
||||
- if (!q->seen) {
|
||||
- q->revalidate = 1;
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static void ehci_queues_rip_unused(EHCIState *ehci, int async)
|
||||
+static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
|
||||
{
|
||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
||||
uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
|
||||
@@ -828,7 +816,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async)
|
||||
q->ts = ehci->last_run_ns;
|
||||
continue;
|
||||
}
|
||||
- if (ehci->last_run_ns < q->ts + maxage) {
|
||||
+ if (!flush && ehci->last_run_ns < q->ts + maxage) {
|
||||
continue;
|
||||
}
|
||||
ehci_free_queue(q);
|
||||
@@ -1684,7 +1672,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
|
||||
ehci_set_usbsts(ehci, USBSTS_REC);
|
||||
}
|
||||
|
||||
- ehci_queues_rip_unused(ehci, async);
|
||||
+ ehci_queues_rip_unused(ehci, async, 0);
|
||||
|
||||
/* Find the head of the list (4.9.1.1) */
|
||||
for(i = 0; i < MAX_QH; i++) {
|
||||
@@ -1769,7 +1757,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
EHCIPacket *p;
|
||||
uint32_t entry, devaddr;
|
||||
EHCIQueue *q;
|
||||
- EHCIqh qh;
|
||||
|
||||
entry = ehci_get_fetch_addr(ehci, async);
|
||||
q = ehci_find_queue_by_qh(ehci, entry, async);
|
||||
@@ -1787,17 +1774,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
}
|
||||
|
||||
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
||||
- (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
||||
- if (q->revalidate && (q->qh.epchar != qh.epchar ||
|
||||
- q->qh.epcap != qh.epcap ||
|
||||
- q->qh.current_qtd != qh.current_qtd)) {
|
||||
- ehci_free_queue(q);
|
||||
- q = ehci_alloc_queue(ehci, entry, async);
|
||||
- q->seen++;
|
||||
- p = NULL;
|
||||
- }
|
||||
- q->qh = qh;
|
||||
- q->revalidate = 0;
|
||||
+ (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
|
||||
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
|
||||
|
||||
devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
|
||||
@@ -2306,7 +2283,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_tag_unused_async(ehci);
|
||||
+ ehci_queues_rip_unused(ehci, async, 1);
|
||||
DPRINTF("ASYNC: doorbell request acknowledged\n");
|
||||
ehci->usbcmd &= ~USBCMD_IAAD;
|
||||
ehci_raise_irq(ehci, USBSTS_IAA);
|
||||
@@ -2359,7 +2336,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);
|
||||
+ ehci_queues_rip_unused(ehci, async, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,84 @@
|
||||
From 1ee48073d05a8a0dfe08ad2853be125a87f176de Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Wed, 29 Aug 2012 10:37:37 +0200
|
||||
Subject: [PATCH 306/366] ehci: Validate qh is not changed unexpectedly by the
|
||||
guest
|
||||
|
||||
-combine the qh check with the check for devaddr changes
|
||||
-also ensure that p gets set to NULL when the queue gets cancelled on
|
||||
devaddr change, which was not done properly before this patch
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 39 ++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 28 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index e7c36f4..35eb441 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -780,6 +780,14 @@ static void ehci_cancel_queue(EHCIQueue *q)
|
||||
} while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
|
||||
}
|
||||
|
||||
+static void ehci_reset_queue(EHCIQueue *q)
|
||||
+{
|
||||
+ trace_usb_ehci_queue_action(q, "reset");
|
||||
+ ehci_cancel_queue(q);
|
||||
+ q->dev = NULL;
|
||||
+ q->qtdaddr = 0;
|
||||
+}
|
||||
+
|
||||
static void ehci_free_queue(EHCIQueue *q)
|
||||
{
|
||||
EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
|
||||
@@ -1755,8 +1763,9 @@ out:
|
||||
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
{
|
||||
EHCIPacket *p;
|
||||
- uint32_t entry, devaddr;
|
||||
+ uint32_t entry, devaddr, endp;
|
||||
EHCIQueue *q;
|
||||
+ EHCIqh qh;
|
||||
|
||||
entry = ehci_get_fetch_addr(ehci, async);
|
||||
q = ehci_find_queue_by_qh(ehci, entry, async);
|
||||
@@ -1774,17 +1783,25 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
}
|
||||
|
||||
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
||||
- (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
|
||||
- ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
|
||||
+ (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
||||
+ ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh);
|
||||
+
|
||||
+ /*
|
||||
+ * The overlay area of the qh should never be changed by the guest,
|
||||
+ * except when idle, in which case the reset is a nop.
|
||||
+ */
|
||||
+ devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR);
|
||||
+ endp = get_field(qh.epchar, QH_EPCHAR_EP);
|
||||
+ if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
|
||||
+ (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
|
||||
+ (memcmp(&qh.current_qtd, &q->qh.current_qtd,
|
||||
+ 9 * sizeof(uint32_t)) != 0) ||
|
||||
+ (q->dev != NULL && q->dev->addr != devaddr)) {
|
||||
+ ehci_reset_queue(q);
|
||||
+ p = NULL;
|
||||
+ }
|
||||
+ q->qh = qh;
|
||||
|
||||
- devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
|
||||
- if (q->dev != NULL && q->dev->addr != devaddr) {
|
||||
- if (!QTAILQ_EMPTY(&q->packets)) {
|
||||
- /* should not happen (guest bug) */
|
||||
- ehci_cancel_queue(q);
|
||||
- }
|
||||
- q->dev = NULL;
|
||||
- }
|
||||
if (q->dev == NULL) {
|
||||
q->dev = ehci_find_device(q->ehci, devaddr);
|
||||
}
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,33 @@
|
||||
From faeefe2a1fdb5895bffb1380b318f3cc396cb057 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 16:21:12 +0200
|
||||
Subject: [PATCH 307/366] ehci: Update copyright headers to reflect recent
|
||||
work
|
||||
|
||||
Update copyright headers to reflect all the work Gerd and I have been doing
|
||||
on the EHCI emulation.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 35eb441..78a248f 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -2,6 +2,11 @@
|
||||
* QEMU USB EHCI Emulation
|
||||
*
|
||||
* Copyright(c) 2008 Emutex Ltd. (address@hidden)
|
||||
+ * Copyright(c) 2011-2012 Red Hat, Inc.
|
||||
+ *
|
||||
+ * Red Hat Authors:
|
||||
+ * Gerd Hoffmann <kraxel@redhat.com>
|
||||
+ * Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* EHCI project was started by Mark Burkley, with contributions by
|
||||
* Niels de Vos. David S. Ahern continued working on it. Kevin Wolf,
|
||||
--
|
||||
1.7.12
|
||||
|
26
0308-ehci-Properly-cleanup-packets-on-cancel.patch
Normal file
26
0308-ehci-Properly-cleanup-packets-on-cancel.patch
Normal file
@ -0,0 +1,26 @@
|
||||
From 95a792a46e8daae4bfb0997f6340bcd8dddea06c Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 15:00:33 +0200
|
||||
Subject: [PATCH 308/366] ehci: Properly cleanup packets on cancel
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 78a248f..4fe85c8 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -747,6 +747,8 @@ static void ehci_free_packet(EHCIPacket *p)
|
||||
trace_usb_ehci_packet_action(p->queue, p, "free");
|
||||
if (p->async == EHCI_ASYNC_INFLIGHT) {
|
||||
usb_cancel_packet(&p->packet);
|
||||
+ usb_packet_unmap(&p->packet, &p->sgl);
|
||||
+ qemu_sglist_destroy(&p->sgl);
|
||||
}
|
||||
QTAILQ_REMOVE(&p->queue->packets, p, next);
|
||||
usb_packet_cleanup(&p->packet);
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,49 @@
|
||||
From 584606864261092041b46806030e4889b747ad41 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 15:18:24 +0200
|
||||
Subject: [PATCH 309/366] ehci: Properly report completed but not yet
|
||||
processed packets to the guest
|
||||
|
||||
Reported packets which have completed before being cancelled as such to the
|
||||
host. Note that the new code path this patch adds is untested since it I've
|
||||
been unable to actually trigger the race which needs this code path.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 4fe85c8..0a6c9ef 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -489,6 +489,9 @@ static const char *ehci_mmio_names[] = {
|
||||
[CONFIGFLAG] = "CONFIGFLAG",
|
||||
};
|
||||
|
||||
+static int ehci_state_executing(EHCIQueue *q);
|
||||
+static int ehci_state_writeback(EHCIQueue *q);
|
||||
+
|
||||
static const char *nr2str(const char **n, size_t len, uint32_t nr)
|
||||
{
|
||||
if (nr < len && n[nr] != NULL) {
|
||||
@@ -750,6 +753,16 @@ static void ehci_free_packet(EHCIPacket *p)
|
||||
usb_packet_unmap(&p->packet, &p->sgl);
|
||||
qemu_sglist_destroy(&p->sgl);
|
||||
}
|
||||
+ if (p->async == EHCI_ASYNC_FINISHED) {
|
||||
+ int state = ehci_get_state(p->queue->ehci, p->queue->async);
|
||||
+ /* This is a normal, but rare condition (cancel racing completion) */
|
||||
+ fprintf(stderr, "EHCI: Warning packet completed but not processed\n");
|
||||
+ ehci_state_executing(p->queue);
|
||||
+ ehci_state_writeback(p->queue);
|
||||
+ ehci_set_state(p->queue->ehci, p->queue->async, state);
|
||||
+ /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */
|
||||
+ return;
|
||||
+ }
|
||||
QTAILQ_REMOVE(&p->queue->packets, p, next);
|
||||
usb_packet_cleanup(&p->packet);
|
||||
g_free(p);
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,47 @@
|
||||
From 6f009493144d09e417997caa13b62a38798dc206 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 31 Aug 2012 10:31:54 +0200
|
||||
Subject: [PATCH 310/366] ehci: check for EHCI_ASYNC_FINISHED first in
|
||||
ehci_free_packet
|
||||
|
||||
Otherwise we'll see the packet free twice in the trace log even though
|
||||
it actually happens only once.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 0a6c9ef..23221d0 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -747,12 +747,6 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
|
||||
|
||||
static void ehci_free_packet(EHCIPacket *p)
|
||||
{
|
||||
- trace_usb_ehci_packet_action(p->queue, p, "free");
|
||||
- if (p->async == EHCI_ASYNC_INFLIGHT) {
|
||||
- usb_cancel_packet(&p->packet);
|
||||
- usb_packet_unmap(&p->packet, &p->sgl);
|
||||
- qemu_sglist_destroy(&p->sgl);
|
||||
- }
|
||||
if (p->async == EHCI_ASYNC_FINISHED) {
|
||||
int state = ehci_get_state(p->queue->ehci, p->queue->async);
|
||||
/* This is a normal, but rare condition (cancel racing completion) */
|
||||
@@ -763,6 +757,12 @@ static void ehci_free_packet(EHCIPacket *p)
|
||||
/* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */
|
||||
return;
|
||||
}
|
||||
+ trace_usb_ehci_packet_action(p->queue, p, "free");
|
||||
+ if (p->async == EHCI_ASYNC_INFLIGHT) {
|
||||
+ usb_cancel_packet(&p->packet);
|
||||
+ usb_packet_unmap(&p->packet, &p->sgl);
|
||||
+ qemu_sglist_destroy(&p->sgl);
|
||||
+ }
|
||||
QTAILQ_REMOVE(&p->queue->packets, p, next);
|
||||
usb_packet_cleanup(&p->packet);
|
||||
g_free(p);
|
||||
--
|
||||
1.7.12
|
||||
|
106
0311-ehci-trace-guest-bugs.patch
Normal file
106
0311-ehci-trace-guest-bugs.patch
Normal file
@ -0,0 +1,106 @@
|
||||
From 044dcae94243d03739c309935a68b646424a4d4e Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 31 Aug 2012 10:44:21 +0200
|
||||
Subject: [PATCH 311/366] ehci: trace guest bugs
|
||||
|
||||
make qemu_queue_{cancel,reset} return the number of packets released,
|
||||
so the caller can figure whenever there have been active packets even
|
||||
though there shouldn't have been any. Add tracepoint to log this.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 26 ++++++++++++++++++++------
|
||||
trace-events | 1 +
|
||||
2 files changed, 21 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 23221d0..4564615 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -716,6 +716,12 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
|
||||
(bool)(sitd->results & SITD_RESULTS_ACTIVE));
|
||||
}
|
||||
|
||||
+static void ehci_trace_guest_bug(EHCIState *s, const char *message)
|
||||
+{
|
||||
+ trace_usb_ehci_guest_bug(message);
|
||||
+ fprintf(stderr, "ehci warning: %s\n", message);
|
||||
+}
|
||||
+
|
||||
static inline bool ehci_enabled(EHCIState *s)
|
||||
{
|
||||
return s->usbcmd & USBCMD_RUNSTOP;
|
||||
@@ -785,27 +791,33 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
|
||||
return q;
|
||||
}
|
||||
|
||||
-static void ehci_cancel_queue(EHCIQueue *q)
|
||||
+static int ehci_cancel_queue(EHCIQueue *q)
|
||||
{
|
||||
EHCIPacket *p;
|
||||
+ int packets = 0;
|
||||
|
||||
p = QTAILQ_FIRST(&q->packets);
|
||||
if (p == NULL) {
|
||||
- return;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
trace_usb_ehci_queue_action(q, "cancel");
|
||||
do {
|
||||
ehci_free_packet(p);
|
||||
+ packets++;
|
||||
} while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
|
||||
+ return packets;
|
||||
}
|
||||
|
||||
-static void ehci_reset_queue(EHCIQueue *q)
|
||||
+static int ehci_reset_queue(EHCIQueue *q)
|
||||
{
|
||||
+ int packets;
|
||||
+
|
||||
trace_usb_ehci_queue_action(q, "reset");
|
||||
- ehci_cancel_queue(q);
|
||||
+ packets = ehci_cancel_queue(q);
|
||||
q->dev = NULL;
|
||||
q->qtdaddr = 0;
|
||||
+ return packets;
|
||||
}
|
||||
|
||||
static void ehci_free_queue(EHCIQueue *q)
|
||||
@@ -1817,7 +1829,9 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
(memcmp(&qh.current_qtd, &q->qh.current_qtd,
|
||||
9 * sizeof(uint32_t)) != 0) ||
|
||||
(q->dev != NULL && q->dev->addr != devaddr)) {
|
||||
- ehci_reset_queue(q);
|
||||
+ if (ehci_reset_queue(q) > 0) {
|
||||
+ ehci_trace_guest_bug(ehci, "guest updated active QH");
|
||||
+ }
|
||||
p = NULL;
|
||||
}
|
||||
q->qh = qh;
|
||||
@@ -1979,8 +1993,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
|
||||
(!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) ||
|
||||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
|
||||
p->qtd.bufptr[0] != qtd.bufptr[0]) {
|
||||
- /* guest bug: guest updated active QH or qTD underneath us */
|
||||
ehci_cancel_queue(q);
|
||||
+ ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD");
|
||||
p = NULL;
|
||||
} else {
|
||||
p->qtd = qtd;
|
||||
diff --git a/trace-events b/trace-events
|
||||
index 8fcbc50..5112a47 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -263,6 +263,7 @@ usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t l
|
||||
usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
|
||||
usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s"
|
||||
usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x"
|
||||
+usb_ehci_guest_bug(const char *reason) "%s"
|
||||
|
||||
# hw/usb/hcd-uhci.c
|
||||
usb_uhci_reset(void) "=== RESET ==="
|
||||
--
|
||||
1.7.12
|
||||
|
48
0312-ehci-add-doorbell-trace-events.patch
Normal file
48
0312-ehci-add-doorbell-trace-events.patch
Normal file
@ -0,0 +1,48 @@
|
||||
From 77e3a7e6bf15a85040101e7c0990dd82abdc9e9c Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 31 Aug 2012 12:41:43 +0200
|
||||
Subject: [PATCH 312/366] ehci: add doorbell trace events
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 3 ++-
|
||||
trace-events | 2 ++
|
||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 4564615..398f5e0 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -1241,6 +1241,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
*/
|
||||
s->async_stepdown = 0;
|
||||
qemu_bh_schedule(s->async_bh);
|
||||
+ trace_usb_ehci_doorbell_ring();
|
||||
}
|
||||
|
||||
if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=
|
||||
@@ -2335,7 +2336,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);
|
||||
- DPRINTF("ASYNC: doorbell request acknowledged\n");
|
||||
+ trace_usb_ehci_doorbell_ack();
|
||||
ehci->usbcmd &= ~USBCMD_IAAD;
|
||||
ehci_raise_irq(ehci, USBSTS_IAA);
|
||||
}
|
||||
diff --git a/trace-events b/trace-events
|
||||
index 5112a47..10bc04e 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -264,6 +264,8 @@ usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
|
||||
usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s"
|
||||
usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x"
|
||||
usb_ehci_guest_bug(const char *reason) "%s"
|
||||
+usb_ehci_doorbell_ring(void) ""
|
||||
+usb_ehci_doorbell_ack(void) ""
|
||||
|
||||
# hw/usb/hcd-uhci.c
|
||||
usb_uhci_reset(void) "=== RESET ==="
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,86 @@
|
||||
From cbbfcc647e26708cdd78c8ddf28d99f8a1e1e6b0 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 10:22:16 +0200
|
||||
Subject: [PATCH 313/366] ehci: Add some additional ehci_trace_guest_bug()
|
||||
calls
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 19 +++++++++++++------
|
||||
1 file changed, 13 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 398f5e0..5a88268 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -820,12 +820,16 @@ static int ehci_reset_queue(EHCIQueue *q)
|
||||
return packets;
|
||||
}
|
||||
|
||||
-static void ehci_free_queue(EHCIQueue *q)
|
||||
+static void ehci_free_queue(EHCIQueue *q, const char *warn)
|
||||
{
|
||||
EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
|
||||
+ int cancelled;
|
||||
|
||||
trace_usb_ehci_queue_action(q, "free");
|
||||
- ehci_cancel_queue(q);
|
||||
+ cancelled = ehci_cancel_queue(q);
|
||||
+ if (warn && cancelled > 0) {
|
||||
+ ehci_trace_guest_bug(q->ehci, warn);
|
||||
+ }
|
||||
QTAILQ_REMOVE(head, q, next);
|
||||
g_free(q);
|
||||
}
|
||||
@@ -847,6 +851,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
|
||||
static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
|
||||
{
|
||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
||||
+ const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL;
|
||||
uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
|
||||
EHCIQueue *q, *tmp;
|
||||
|
||||
@@ -859,7 +864,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
|
||||
if (!flush && ehci->last_run_ns < q->ts + maxage) {
|
||||
continue;
|
||||
}
|
||||
- ehci_free_queue(q);
|
||||
+ ehci_free_queue(q, warn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,17 +877,18 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
|
||||
if (q->dev != dev) {
|
||||
continue;
|
||||
}
|
||||
- ehci_free_queue(q);
|
||||
+ ehci_free_queue(q, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_queues_rip_all(EHCIState *ehci, int async)
|
||||
{
|
||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
||||
+ const char *warn = async ? "guest stopped busy async schedule" : NULL;
|
||||
EHCIQueue *q, *tmp;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
|
||||
- ehci_free_queue(q);
|
||||
+ ehci_free_queue(q, warn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1549,7 +1555,8 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
|
||||
p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
|
||||
if (p->tbytes > BUFF_SIZE) {
|
||||
- fprintf(stderr, "Request for more bytes than allowed\n");
|
||||
+ ehci_trace_guest_bug(p->queue->ehci,
|
||||
+ "guest requested more bytes than allowed");
|
||||
return USB_RET_PROCERR;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
117
0314-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch
Normal file
117
0314-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch
Normal file
@ -0,0 +1,117 @@
|
||||
From 68851693ee59d3f17c14983902076a5ef49e2e80 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 11:01:13 +0200
|
||||
Subject: [PATCH 314/366] ehci: Fix memory leak in handling of NAK-ed packets
|
||||
|
||||
Currently each time we try to execute a NAK-ed packet we redo
|
||||
ehci_init_transfer, and usb_packet_map, re-allocing (without freeing) the
|
||||
sg list every time.
|
||||
|
||||
This patch fixes this, it does this by introducing another async state, so
|
||||
that we also properly cleanup a NAK-ed packet on cancel.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 38 +++++++++++++++++++++++++++-----------
|
||||
1 file changed, 27 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 5a88268..d87aca8 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -345,6 +345,7 @@ typedef struct EHCIState EHCIState;
|
||||
|
||||
enum async_state {
|
||||
EHCI_ASYNC_NONE = 0,
|
||||
+ EHCI_ASYNC_INITIALIZED,
|
||||
EHCI_ASYNC_INFLIGHT,
|
||||
EHCI_ASYNC_FINISHED,
|
||||
};
|
||||
@@ -764,6 +765,10 @@ static void ehci_free_packet(EHCIPacket *p)
|
||||
return;
|
||||
}
|
||||
trace_usb_ehci_packet_action(p->queue, p, "free");
|
||||
+ if (p->async == EHCI_ASYNC_INITIALIZED) {
|
||||
+ usb_packet_unmap(&p->packet, &p->sgl);
|
||||
+ qemu_sglist_destroy(&p->sgl);
|
||||
+ }
|
||||
if (p->async == EHCI_ASYNC_INFLIGHT) {
|
||||
usb_cancel_packet(&p->packet);
|
||||
usb_packet_unmap(&p->packet, &p->sgl);
|
||||
@@ -1485,8 +1490,8 @@ static void ehci_execute_complete(EHCIQueue *q)
|
||||
|
||||
assert(p != NULL);
|
||||
assert(p->qtdaddr == q->qtdaddr);
|
||||
- assert(p->async != EHCI_ASYNC_INFLIGHT);
|
||||
- p->async = EHCI_ASYNC_NONE;
|
||||
+ assert(p->async == EHCI_ASYNC_INITIALIZED ||
|
||||
+ p->async == EHCI_ASYNC_FINISHED);
|
||||
|
||||
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
|
||||
q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
|
||||
@@ -1531,6 +1536,7 @@ static void ehci_execute_complete(EHCIQueue *q)
|
||||
ehci_finish_transfer(q, p->usb_status);
|
||||
usb_packet_unmap(&p->packet, &p->sgl);
|
||||
qemu_sglist_destroy(&p->sgl);
|
||||
+ p->async = EHCI_ASYNC_NONE;
|
||||
|
||||
q->qh.token ^= QTD_TOKEN_DTOGGLE;
|
||||
q->qh.token &= ~QTD_TOKEN_ACTIVE;
|
||||
@@ -1548,6 +1554,9 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
int ret;
|
||||
int endp;
|
||||
|
||||
+ assert(p->async == EHCI_ASYNC_NONE ||
|
||||
+ p->async == EHCI_ASYNC_INITIALIZED);
|
||||
+
|
||||
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
|
||||
fprintf(stderr, "Attempting to execute inactive qtd\n");
|
||||
return USB_RET_PROCERR;
|
||||
@@ -1576,15 +1585,18 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
break;
|
||||
}
|
||||
|
||||
- if (ehci_init_transfer(p) != 0) {
|
||||
- return USB_RET_PROCERR;
|
||||
- }
|
||||
-
|
||||
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
|
||||
ep = usb_ep_get(p->queue->dev, p->pid, endp);
|
||||
|
||||
- usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
|
||||
- usb_packet_map(&p->packet, &p->sgl);
|
||||
+ if (p->async == EHCI_ASYNC_NONE) {
|
||||
+ if (ehci_init_transfer(p) != 0) {
|
||||
+ return USB_RET_PROCERR;
|
||||
+ }
|
||||
+
|
||||
+ usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
|
||||
+ usb_packet_map(&p->packet, &p->sgl);
|
||||
+ p->async = EHCI_ASYNC_INITIALIZED;
|
||||
+ }
|
||||
|
||||
trace_usb_ehci_packet_action(p->queue, p, action);
|
||||
ret = usb_handle_packet(p->queue->dev, &p->packet);
|
||||
@@ -2021,11 +2033,15 @@ 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) */
|
||||
- ehci_set_state(q->ehci, q->async, EST_EXECUTE);
|
||||
- break;
|
||||
+ ehci_set_state(q->ehci, q->async, EST_EXECUTE);
|
||||
+ break;
|
||||
case EHCI_ASYNC_INFLIGHT:
|
||||
- /* Unfinyshed async handled packet, go horizontal */
|
||||
+ /* Unfinished async handled packet, go horizontal */
|
||||
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||
break;
|
||||
case EHCI_ASYNC_FINISHED:
|
||||
--
|
||||
1.7.12
|
||||
|
54
0315-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch
Normal file
54
0315-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch
Normal file
@ -0,0 +1,54 @@
|
||||
From 1599d0b01712fb16c3ad291b653a31f768f7f5ef Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 11:35:58 +0200
|
||||
Subject: [PATCH 315/366] ehci: Handle USB_RET_PROCERR in ehci_fill_queue
|
||||
|
||||
USB_RET_PROCERR can be triggered by the guest (by for example requesting more
|
||||
then BUFFSIZE bytes), so don't assert on it.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index d87aca8..2534394 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -2076,7 +2076,7 @@ static int ehci_state_horizqh(EHCIQueue *q)
|
||||
return again;
|
||||
}
|
||||
|
||||
-static void ehci_fill_queue(EHCIPacket *p)
|
||||
+static int ehci_fill_queue(EHCIPacket *p)
|
||||
{
|
||||
EHCIQueue *q = p->queue;
|
||||
EHCIqtd qtd = p->qtd;
|
||||
@@ -2100,9 +2100,13 @@ static void ehci_fill_queue(EHCIPacket *p)
|
||||
p->qtdaddr = qtdaddr;
|
||||
p->qtd = qtd;
|
||||
p->usb_status = ehci_execute(p, "queue");
|
||||
+ if (p->usb_status == USB_RET_PROCERR) {
|
||||
+ break;
|
||||
+ }
|
||||
assert(p->usb_status == USB_RET_ASYNC);
|
||||
p->async = EHCI_ASYNC_INFLIGHT;
|
||||
}
|
||||
+ return p->usb_status;
|
||||
}
|
||||
|
||||
static int ehci_state_execute(EHCIQueue *q)
|
||||
@@ -2144,8 +2148,7 @@ 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 = 1;
|
||||
- ehci_fill_queue(p);
|
||||
+ again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,35 @@
|
||||
From d17b1ad80cba3354b3eca5b8464bf7bb3f8e95c1 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 12:17:48 +0200
|
||||
Subject: [PATCH 316/366] ehci: Correct a comment in fetchqtd packet
|
||||
processing
|
||||
|
||||
Since my previous comment said "Should never happen", I tried changing the
|
||||
next line to an assert(0), which did not go well, which as the new comments
|
||||
explains is logical if you think about it for a moment.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-ehci.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
||||
index 2534394..2f3e9c0 100644
|
||||
--- a/hw/usb/hcd-ehci.c
|
||||
+++ b/hw/usb/hcd-ehci.c
|
||||
@@ -2045,7 +2045,10 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
|
||||
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||
break;
|
||||
case EHCI_ASYNC_FINISHED:
|
||||
- /* Should never happen, as this case is caught by fetchqh */
|
||||
+ /*
|
||||
+ * We get here when advqueue moves to a packet which is already
|
||||
+ * finished, which can happen with packets queued up by fill_queue
|
||||
+ */
|
||||
ehci_set_state(q->ehci, q->async, EST_EXECUTING);
|
||||
break;
|
||||
}
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,44 @@
|
||||
From a15db9c6d428a756f6ad4055334e476cd90b31f6 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Fri, 17 Aug 2012 17:27:08 +0200
|
||||
Subject: [PATCH 317/366] usb-redir: Never return USB_RET_NAK for async
|
||||
handled packets
|
||||
|
||||
USB_RET_NAK is not a valid response for async handled packets (and will
|
||||
trigger an assert as such).
|
||||
|
||||
Also drop the warning when receiving a status of cancelled for packets not
|
||||
cancelled by qemu itself, this can happen when a device gets unredirected
|
||||
by the usbredir-host while transfers are pending.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 1460515..9ba964e 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -1055,11 +1055,14 @@ static int usbredir_handle_status(USBRedirDevice *dev,
|
||||
case usb_redir_stall:
|
||||
return USB_RET_STALL;
|
||||
case usb_redir_cancelled:
|
||||
- WARNING("returning cancelled packet to HC?\n");
|
||||
- return USB_RET_NAK;
|
||||
+ /*
|
||||
+ * When the usbredir-host unredirects a device, it will report a status
|
||||
+ * of cancelled for all pending packets, followed by a disconnect msg.
|
||||
+ */
|
||||
+ return USB_RET_IOERROR;
|
||||
case usb_redir_inval:
|
||||
WARNING("got invalid param error from usb-host?\n");
|
||||
- return USB_RET_NAK;
|
||||
+ return USB_RET_IOERROR;
|
||||
case usb_redir_babble:
|
||||
return USB_RET_BABBLE;
|
||||
case usb_redir_ioerror:
|
||||
--
|
||||
1.7.12
|
||||
|
181
0318-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch
Normal file
181
0318-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch
Normal file
@ -0,0 +1,181 @@
|
||||
From acf269a7bbed7c969eb9be02943f7e4b52196a8f Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Thu, 23 Aug 2012 16:37:19 +0200
|
||||
Subject: [PATCH 318/366] usb-redir: Don't delay handling of open events to a
|
||||
bottom half
|
||||
|
||||
There is no need for this, and doing so means that a backend trying to
|
||||
write immediately after an open event will see qemu_chr_be_can_write
|
||||
returning 0, which not all backends handle well as there is no wakeup
|
||||
mechanism to detect when the frontend does become writable.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 100 +++++++++++++++++++++++++++++-------------------------
|
||||
1 file changed, 53 insertions(+), 47 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 9ba964e..8ac8637 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -79,8 +79,8 @@ struct USBRedirDevice {
|
||||
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
|
||||
const uint8_t *read_buf;
|
||||
int read_buf_size;
|
||||
- /* For async handling of open/close */
|
||||
- QEMUBH *open_close_bh;
|
||||
+ /* For async handling of close */
|
||||
+ QEMUBH *chardev_close_bh;
|
||||
/* To delay the usb attach in case of quick chardev close + open */
|
||||
QEMUTimer *attach_timer;
|
||||
int64_t next_attach_time;
|
||||
@@ -794,18 +794,11 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
* from within the USBDevice data / control packet callbacks and doing a
|
||||
* usb_detach from within these callbacks is not a good idea.
|
||||
*
|
||||
- * So we use a bh handler to take care of close events. We also handle
|
||||
- * open events from this callback to make sure that a close directly followed
|
||||
- * by an open gets handled in the right order.
|
||||
+ * So we use a bh handler to take care of close events.
|
||||
*/
|
||||
-static void usbredir_open_close_bh(void *opaque)
|
||||
+static void usbredir_chardev_close_bh(void *opaque)
|
||||
{
|
||||
USBRedirDevice *dev = opaque;
|
||||
- uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
|
||||
- char version[32];
|
||||
-
|
||||
- strcpy(version, "qemu usb-redir guest ");
|
||||
- pstrcat(version, sizeof(version), qemu_get_version());
|
||||
|
||||
usbredir_device_disconnect(dev);
|
||||
|
||||
@@ -813,36 +806,47 @@ static void usbredir_open_close_bh(void *opaque)
|
||||
usbredirparser_destroy(dev->parser);
|
||||
dev->parser = NULL;
|
||||
}
|
||||
+}
|
||||
|
||||
- if (dev->cs->opened) {
|
||||
- dev->parser = qemu_oom_check(usbredirparser_create());
|
||||
- dev->parser->priv = dev;
|
||||
- dev->parser->log_func = usbredir_log;
|
||||
- dev->parser->read_func = usbredir_read;
|
||||
- dev->parser->write_func = usbredir_write;
|
||||
- dev->parser->hello_func = usbredir_hello;
|
||||
- dev->parser->device_connect_func = usbredir_device_connect;
|
||||
- dev->parser->device_disconnect_func = usbredir_device_disconnect;
|
||||
- dev->parser->interface_info_func = usbredir_interface_info;
|
||||
- dev->parser->ep_info_func = usbredir_ep_info;
|
||||
- dev->parser->configuration_status_func = usbredir_configuration_status;
|
||||
- dev->parser->alt_setting_status_func = usbredir_alt_setting_status;
|
||||
- dev->parser->iso_stream_status_func = usbredir_iso_stream_status;
|
||||
- dev->parser->interrupt_receiving_status_func =
|
||||
- usbredir_interrupt_receiving_status;
|
||||
- dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
|
||||
- dev->parser->control_packet_func = usbredir_control_packet;
|
||||
- dev->parser->bulk_packet_func = usbredir_bulk_packet;
|
||||
- dev->parser->iso_packet_func = usbredir_iso_packet;
|
||||
- dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
|
||||
- dev->read_buf = NULL;
|
||||
- dev->read_buf_size = 0;
|
||||
+static void usbredir_chardev_open(USBRedirDevice *dev)
|
||||
+{
|
||||
+ uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
|
||||
+ char version[32];
|
||||
|
||||
- usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
|
||||
- usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
|
||||
- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0);
|
||||
- usbredirparser_do_write(dev->parser);
|
||||
- }
|
||||
+ /* Make sure any pending closes are handled (no-op if none pending) */
|
||||
+ usbredir_chardev_close_bh(dev);
|
||||
+ qemu_bh_cancel(dev->chardev_close_bh);
|
||||
+
|
||||
+ 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;
|
||||
+ dev->parser->read_func = usbredir_read;
|
||||
+ dev->parser->write_func = usbredir_write;
|
||||
+ dev->parser->hello_func = usbredir_hello;
|
||||
+ dev->parser->device_connect_func = usbredir_device_connect;
|
||||
+ dev->parser->device_disconnect_func = usbredir_device_disconnect;
|
||||
+ dev->parser->interface_info_func = usbredir_interface_info;
|
||||
+ dev->parser->ep_info_func = usbredir_ep_info;
|
||||
+ dev->parser->configuration_status_func = usbredir_configuration_status;
|
||||
+ dev->parser->alt_setting_status_func = usbredir_alt_setting_status;
|
||||
+ dev->parser->iso_stream_status_func = usbredir_iso_stream_status;
|
||||
+ dev->parser->interrupt_receiving_status_func =
|
||||
+ usbredir_interrupt_receiving_status;
|
||||
+ dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
|
||||
+ dev->parser->control_packet_func = usbredir_control_packet;
|
||||
+ dev->parser->bulk_packet_func = usbredir_bulk_packet;
|
||||
+ dev->parser->iso_packet_func = usbredir_iso_packet;
|
||||
+ dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
|
||||
+ dev->read_buf = NULL;
|
||||
+ dev->read_buf_size = 0;
|
||||
+
|
||||
+ usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
|
||||
+ usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
|
||||
+ usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0);
|
||||
+ usbredirparser_do_write(dev->parser);
|
||||
}
|
||||
|
||||
static void usbredir_do_attach(void *opaque)
|
||||
@@ -866,13 +870,13 @@ static int usbredir_chardev_can_read(void *opaque)
|
||||
{
|
||||
USBRedirDevice *dev = opaque;
|
||||
|
||||
- if (dev->parser) {
|
||||
- /* usbredir_parser_do_read will consume *all* data we give it */
|
||||
- return 1024 * 1024;
|
||||
- } else {
|
||||
- /* usbredir_open_close_bh hasn't handled the open event yet */
|
||||
+ if (!dev->parser) {
|
||||
+ WARNING("chardev_can_read called on non open chardev!\n");
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+ /* usbredir_parser_do_read will consume *all* data we give it */
|
||||
+ return 1024 * 1024;
|
||||
}
|
||||
|
||||
static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size)
|
||||
@@ -896,8 +900,10 @@ static void usbredir_chardev_event(void *opaque, int event)
|
||||
|
||||
switch (event) {
|
||||
case CHR_EVENT_OPENED:
|
||||
+ usbredir_chardev_open(dev);
|
||||
+ break;
|
||||
case CHR_EVENT_CLOSED:
|
||||
- qemu_bh_schedule(dev->open_close_bh);
|
||||
+ qemu_bh_schedule(dev->chardev_close_bh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -945,7 +951,7 @@ static int usbredir_initfn(USBDevice *udev)
|
||||
}
|
||||
}
|
||||
|
||||
- dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev);
|
||||
+ 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->asyncq);
|
||||
@@ -984,7 +990,7 @@ static void usbredir_handle_destroy(USBDevice *udev)
|
||||
qemu_chr_fe_close(dev->cs);
|
||||
qemu_chr_delete(dev->cs);
|
||||
/* Note must be done after qemu_chr_close, as that causes a close event */
|
||||
- qemu_bh_delete(dev->open_close_bh);
|
||||
+ qemu_bh_delete(dev->chardev_close_bh);
|
||||
|
||||
qemu_del_timer(dev->attach_timer);
|
||||
qemu_free_timer(dev->attach_timer);
|
||||
--
|
||||
1.7.12
|
||||
|
73
0319-usb-redir-Get-rid-of-async-struct-get-member.patch
Normal file
73
0319-usb-redir-Get-rid-of-async-struct-get-member.patch
Normal file
@ -0,0 +1,73 @@
|
||||
From 5f83bc6b7bf54271bc1e3460b2e6f790407964e0 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 27 Aug 2012 16:33:08 +0200
|
||||
Subject: [PATCH 319/366] usb-redir: Get rid of async-struct get member
|
||||
|
||||
This is a preparation patch for completely getting rid of the async-packet
|
||||
struct in usb-redir, instead relying on the (new) per ep queues in the
|
||||
qemu usb core.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 9 +++------
|
||||
1 file changed, 3 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 8ac8637..4121983 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* USB redirector usb-guest
|
||||
*
|
||||
- * Copyright (c) 2011 Red Hat, Inc.
|
||||
+ * Copyright (c) 2011-2012 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat Authors:
|
||||
* Hans de Goede <hdegoede@redhat.com>
|
||||
@@ -99,7 +99,6 @@ struct AsyncURB {
|
||||
USBRedirDevice *dev;
|
||||
USBPacket *packet;
|
||||
uint32_t packet_id;
|
||||
- int get;
|
||||
union {
|
||||
struct usb_redir_control_packet_header control_packet;
|
||||
struct usb_redir_bulk_packet_header bulk_packet;
|
||||
@@ -682,7 +681,6 @@ static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
|
||||
|
||||
DPRINTF("get config id %u\n", aurb->packet_id);
|
||||
|
||||
- aurb->get = 1;
|
||||
usbredirparser_send_get_configuration(dev->parser, aurb->packet_id);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
@@ -731,7 +729,6 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
|
||||
DPRINTF("get interface %d id %u\n", interface, aurb->packet_id);
|
||||
|
||||
get_alt.interface = interface;
|
||||
- aurb->get = 1;
|
||||
usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id,
|
||||
&get_alt);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
@@ -1253,7 +1250,7 @@ static void usbredir_configuration_status(void *priv, uint32_t id,
|
||||
return;
|
||||
}
|
||||
if (aurb->packet) {
|
||||
- if (aurb->get) {
|
||||
+ if (dev->dev.setup_buf[0] & USB_DIR_IN) {
|
||||
dev->dev.data_buf[0] = config_status->configuration;
|
||||
len = 1;
|
||||
}
|
||||
@@ -1281,7 +1278,7 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||
return;
|
||||
}
|
||||
if (aurb->packet) {
|
||||
- if (aurb->get) {
|
||||
+ if (dev->dev.setup_buf[0] & USB_DIR_IN) {
|
||||
dev->dev.data_buf[0] = alt_setting_status->alt;
|
||||
len = 1;
|
||||
}
|
||||
--
|
||||
1.7.12
|
||||
|
107
0320-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch
Normal file
107
0320-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch
Normal file
@ -0,0 +1,107 @@
|
||||
From 3240adfcb041efcb11b4cbf4b08dc86be52b8ffc Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 09:05:38 +0200
|
||||
Subject: [PATCH 320/366] usb-redir: Get rid of local shadow copy of packet
|
||||
headers
|
||||
|
||||
The shadow copy only serves as an extra check (besides the packet-id) to
|
||||
ensure the packet we get back is a reply to the packet we think it is.
|
||||
|
||||
This check has never triggered in all the time usb-redir is in use now,
|
||||
and since the verified data in the returned packet-header is not used
|
||||
otherwise, removing the check does not open any possibilities for the
|
||||
usbredirhost to confuse us.
|
||||
|
||||
This is a preparation patch for completely getting rid of the async-packet
|
||||
struct in usb-redir, instead relying on the (new) per ep queues in the
|
||||
qemu usb core.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 27 ---------------------------
|
||||
1 file changed, 27 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 4121983..816a19a 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -99,11 +99,6 @@ struct AsyncURB {
|
||||
USBRedirDevice *dev;
|
||||
USBPacket *packet;
|
||||
uint32_t packet_id;
|
||||
- union {
|
||||
- struct usb_redir_control_packet_header control_packet;
|
||||
- struct usb_redir_bulk_packet_header bulk_packet;
|
||||
- struct usb_redir_interrupt_packet_header interrupt_packet;
|
||||
- };
|
||||
QTAILQ_ENTRY(AsyncURB)next;
|
||||
};
|
||||
|
||||
@@ -510,7 +505,6 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
|
||||
bulk_packet.endpoint = ep;
|
||||
bulk_packet.length = p->iov.size;
|
||||
bulk_packet.stream_id = 0;
|
||||
- aurb->bulk_packet = bulk_packet;
|
||||
|
||||
if (ep & USB_DIR_IN) {
|
||||
usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
|
||||
@@ -591,7 +585,6 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
|
||||
|
||||
interrupt_packet.endpoint = ep;
|
||||
interrupt_packet.length = p->iov.size;
|
||||
- aurb->interrupt_packet = interrupt_packet;
|
||||
|
||||
usb_packet_copy(p, buf, p->iov.size);
|
||||
usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
|
||||
@@ -772,7 +765,6 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
control_packet.value = value;
|
||||
control_packet.index = index;
|
||||
control_packet.length = length;
|
||||
- aurb->control_packet = control_packet;
|
||||
|
||||
if (control_packet.requesttype & USB_DIR_IN) {
|
||||
usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
|
||||
@@ -1353,14 +1345,6 @@ static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
return;
|
||||
}
|
||||
|
||||
- aurb->control_packet.status = control_packet->status;
|
||||
- aurb->control_packet.length = control_packet->length;
|
||||
- if (memcmp(&aurb->control_packet, control_packet,
|
||||
- sizeof(*control_packet))) {
|
||||
- ERROR("return control packet mismatch, please report this!\n");
|
||||
- len = USB_RET_NAK;
|
||||
- }
|
||||
-
|
||||
if (aurb->packet) {
|
||||
len = usbredir_handle_status(dev, control_packet->status, len);
|
||||
if (len > 0) {
|
||||
@@ -1398,12 +1382,6 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
|
||||
return;
|
||||
}
|
||||
|
||||
- if (aurb->bulk_packet.endpoint != bulk_packet->endpoint ||
|
||||
- aurb->bulk_packet.stream_id != bulk_packet->stream_id) {
|
||||
- ERROR("return bulk packet mismatch, please report this!\n");
|
||||
- len = USB_RET_NAK;
|
||||
- }
|
||||
-
|
||||
if (aurb->packet) {
|
||||
len = usbredir_handle_status(dev, bulk_packet->status, len);
|
||||
if (len > 0) {
|
||||
@@ -1482,11 +1460,6 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
|
||||
return;
|
||||
}
|
||||
|
||||
- if (aurb->interrupt_packet.endpoint != interrupt_packet->endpoint) {
|
||||
- ERROR("return int packet mismatch, please report this!\n");
|
||||
- len = USB_RET_NAK;
|
||||
- }
|
||||
-
|
||||
if (aurb->packet) {
|
||||
aurb->packet->result = usbredir_handle_status(dev,
|
||||
interrupt_packet->status, len);
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,38 @@
|
||||
From 1b1c99626404328b571e1f6c18b50f9bed9c2e2c Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 09:08:45 +0200
|
||||
Subject: [PATCH 321/366] usb-redir: Get rid of unused async-struct dev member
|
||||
|
||||
This is a preparation patch for completely getting rid of the async-packet
|
||||
struct in usb-redir, instead relying on the (new) per ep queues in the
|
||||
qemu usb core.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 816a19a..4a23b82 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -96,7 +96,6 @@ struct USBRedirDevice {
|
||||
};
|
||||
|
||||
struct AsyncURB {
|
||||
- USBRedirDevice *dev;
|
||||
USBPacket *packet;
|
||||
uint32_t packet_id;
|
||||
QTAILQ_ENTRY(AsyncURB)next;
|
||||
@@ -255,7 +254,6 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
|
||||
static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p)
|
||||
{
|
||||
AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB));
|
||||
- aurb->dev = dev;
|
||||
aurb->packet = p;
|
||||
aurb->packet_id = dev->packet_id;
|
||||
QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next);
|
||||
--
|
||||
1.7.12
|
||||
|
499
0322-usb-redir-Move-to-core-packet-id-and-queue-handling.patch
Normal file
499
0322-usb-redir-Move-to-core-packet-id-and-queue-handling.patch
Normal file
@ -0,0 +1,499 @@
|
||||
From 69642884acc4f5d5b92e16d94fdae50765d1eba7 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 11:30:13 +0200
|
||||
Subject: [PATCH 322/366] usb-redir: Move to core packet id and queue handling
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 226 ++++++++++++++++++++++--------------------------------
|
||||
1 file changed, 92 insertions(+), 134 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 4a23b82..1ce994c 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -43,7 +43,7 @@
|
||||
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
|
||||
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
|
||||
|
||||
-typedef struct AsyncURB AsyncURB;
|
||||
+typedef struct Cancelled Cancelled;
|
||||
typedef struct USBRedirDevice USBRedirDevice;
|
||||
|
||||
/* Struct to hold buffered packets (iso or int input packets) */
|
||||
@@ -86,8 +86,7 @@ struct USBRedirDevice {
|
||||
int64_t next_attach_time;
|
||||
struct usbredirparser *parser;
|
||||
struct endp_data endpoint[MAX_ENDPOINTS];
|
||||
- uint32_t packet_id;
|
||||
- QTAILQ_HEAD(, AsyncURB) asyncq;
|
||||
+ QTAILQ_HEAD(, Cancelled) cancelled;
|
||||
/* Data for device filtering */
|
||||
struct usb_redir_device_connect_header device_info;
|
||||
struct usb_redir_interface_info_header interface_info;
|
||||
@@ -95,10 +94,9 @@ struct USBRedirDevice {
|
||||
int filter_rules_count;
|
||||
};
|
||||
|
||||
-struct AsyncURB {
|
||||
- USBPacket *packet;
|
||||
- uint32_t packet_id;
|
||||
- QTAILQ_ENTRY(AsyncURB)next;
|
||||
+struct Cancelled {
|
||||
+ uint64_t id;
|
||||
+ QTAILQ_ENTRY(Cancelled)next;
|
||||
};
|
||||
|
||||
static void usbredir_hello(void *priv, struct usb_redir_hello_header *h);
|
||||
@@ -248,57 +246,58 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
|
||||
}
|
||||
|
||||
/*
|
||||
- * Async and buffered packets helpers
|
||||
+ * Cancelled and buffered packets helpers
|
||||
*/
|
||||
|
||||
-static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p)
|
||||
+static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
|
||||
{
|
||||
- AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB));
|
||||
- aurb->packet = p;
|
||||
- aurb->packet_id = dev->packet_id;
|
||||
- QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next);
|
||||
- dev->packet_id++;
|
||||
+ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||
+ Cancelled *c;
|
||||
|
||||
- return aurb;
|
||||
-}
|
||||
+ DPRINTF("cancel packet id %"PRIu64"\n", p->id);
|
||||
|
||||
-static void async_free(USBRedirDevice *dev, AsyncURB *aurb)
|
||||
-{
|
||||
- QTAILQ_REMOVE(&dev->asyncq, aurb, next);
|
||||
- g_free(aurb);
|
||||
+ c = g_malloc0(sizeof(Cancelled));
|
||||
+ c->id = p->id;
|
||||
+ QTAILQ_INSERT_TAIL(&dev->cancelled, c, next);
|
||||
+
|
||||
+ usbredirparser_send_cancel_data_packet(dev->parser, p->id);
|
||||
+ usbredirparser_do_write(dev->parser);
|
||||
}
|
||||
|
||||
-static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id)
|
||||
+static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id)
|
||||
{
|
||||
- AsyncURB *aurb;
|
||||
+ Cancelled *c;
|
||||
+
|
||||
+ if (!dev->dev.attached) {
|
||||
+ return 1; /* Treat everything as cancelled after a disconnect */
|
||||
+ }
|
||||
|
||||
- QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
|
||||
- if (aurb->packet_id == packet_id) {
|
||||
- return aurb;
|
||||
+ QTAILQ_FOREACH(c, &dev->cancelled, next) {
|
||||
+ if (c->id == id) {
|
||||
+ QTAILQ_REMOVE(&dev->cancelled, c, next);
|
||||
+ g_free(c);
|
||||
+ return 1;
|
||||
}
|
||||
}
|
||||
- DPRINTF("could not find async urb for packet_id %u\n", packet_id);
|
||||
- return NULL;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
-static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
|
||||
+static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev,
|
||||
+ uint8_t ep, uint64_t id)
|
||||
{
|
||||
- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||
- AsyncURB *aurb;
|
||||
-
|
||||
- QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
|
||||
- if (p != aurb->packet) {
|
||||
- continue;
|
||||
- }
|
||||
+ USBPacket *p;
|
||||
|
||||
- DPRINTF("async cancel id %u\n", aurb->packet_id);
|
||||
- usbredirparser_send_cancel_data_packet(dev->parser, aurb->packet_id);
|
||||
- usbredirparser_do_write(dev->parser);
|
||||
+ if (usbredir_is_cancelled(dev, id)) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
|
||||
- /* Mark it as dead */
|
||||
- aurb->packet = NULL;
|
||||
- break;
|
||||
+ p = usb_ep_find_packet_by_id(&dev->dev,
|
||||
+ (ep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT,
|
||||
+ ep & 0x0f, id);
|
||||
+ if (p == NULL) {
|
||||
+ ERROR("could not find packet with id %"PRIu64"\n", id);
|
||||
}
|
||||
+ return p;
|
||||
}
|
||||
|
||||
static void bufp_alloc(USBRedirDevice *dev,
|
||||
@@ -494,24 +493,22 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
|
||||
static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
|
||||
uint8_t ep)
|
||||
{
|
||||
- AsyncURB *aurb = async_alloc(dev, p);
|
||||
struct usb_redir_bulk_packet_header bulk_packet;
|
||||
|
||||
- DPRINTF("bulk-out ep %02X len %zd id %u\n", ep,
|
||||
- p->iov.size, aurb->packet_id);
|
||||
+ DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id);
|
||||
|
||||
bulk_packet.endpoint = ep;
|
||||
bulk_packet.length = p->iov.size;
|
||||
bulk_packet.stream_id = 0;
|
||||
|
||||
if (ep & USB_DIR_IN) {
|
||||
- usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
|
||||
+ usbredirparser_send_bulk_packet(dev->parser, p->id,
|
||||
&bulk_packet, NULL, 0);
|
||||
} else {
|
||||
uint8_t buf[p->iov.size];
|
||||
usb_packet_copy(p, buf, p->iov.size);
|
||||
usbredir_log_data(dev, "bulk data out:", buf, p->iov.size);
|
||||
- usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
|
||||
+ usbredirparser_send_bulk_packet(dev->parser, p->id,
|
||||
&bulk_packet, buf, p->iov.size);
|
||||
}
|
||||
usbredirparser_do_write(dev->parser);
|
||||
@@ -574,19 +571,18 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
|
||||
return len;
|
||||
} else {
|
||||
/* Output interrupt endpoint, normal async operation */
|
||||
- AsyncURB *aurb = async_alloc(dev, p);
|
||||
struct usb_redir_interrupt_packet_header interrupt_packet;
|
||||
uint8_t buf[p->iov.size];
|
||||
|
||||
- DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size,
|
||||
- aurb->packet_id);
|
||||
+ DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
|
||||
+ p->iov.size, p->id);
|
||||
|
||||
interrupt_packet.endpoint = ep;
|
||||
interrupt_packet.length = p->iov.size;
|
||||
|
||||
usb_packet_copy(p, buf, p->iov.size);
|
||||
usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
|
||||
- usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id,
|
||||
+ usbredirparser_send_interrupt_packet(dev->parser, p->id,
|
||||
&interrupt_packet, buf, p->iov.size);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
@@ -640,10 +636,9 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
|
||||
int config)
|
||||
{
|
||||
struct usb_redir_set_configuration_header set_config;
|
||||
- AsyncURB *aurb = async_alloc(dev, p);
|
||||
int i;
|
||||
|
||||
- DPRINTF("set config %d id %u\n", config, aurb->packet_id);
|
||||
+ DPRINTF("set config %d id %"PRIu64"\n", config, p->id);
|
||||
|
||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||
switch (dev->endpoint[i].type) {
|
||||
@@ -660,19 +655,16 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
|
||||
}
|
||||
|
||||
set_config.configuration = config;
|
||||
- usbredirparser_send_set_configuration(dev->parser, aurb->packet_id,
|
||||
- &set_config);
|
||||
+ usbredirparser_send_set_configuration(dev->parser, p->id, &set_config);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
}
|
||||
|
||||
static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
|
||||
{
|
||||
- AsyncURB *aurb = async_alloc(dev, p);
|
||||
-
|
||||
- DPRINTF("get config id %u\n", aurb->packet_id);
|
||||
+ DPRINTF("get config id %"PRIu64"\n", p->id);
|
||||
|
||||
- usbredirparser_send_get_configuration(dev->parser, aurb->packet_id);
|
||||
+ usbredirparser_send_get_configuration(dev->parser, p->id);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
}
|
||||
@@ -681,11 +673,9 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
|
||||
int interface, int alt)
|
||||
{
|
||||
struct usb_redir_set_alt_setting_header set_alt;
|
||||
- AsyncURB *aurb = async_alloc(dev, p);
|
||||
int i;
|
||||
|
||||
- DPRINTF("set interface %d alt %d id %u\n", interface, alt,
|
||||
- aurb->packet_id);
|
||||
+ DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id);
|
||||
|
||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||
if (dev->endpoint[i].interface == interface) {
|
||||
@@ -705,8 +695,7 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
|
||||
|
||||
set_alt.interface = interface;
|
||||
set_alt.alt = alt;
|
||||
- usbredirparser_send_set_alt_setting(dev->parser, aurb->packet_id,
|
||||
- &set_alt);
|
||||
+ usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
}
|
||||
@@ -715,13 +704,11 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
|
||||
int interface)
|
||||
{
|
||||
struct usb_redir_get_alt_setting_header get_alt;
|
||||
- AsyncURB *aurb = async_alloc(dev, p);
|
||||
|
||||
- DPRINTF("get interface %d id %u\n", interface, aurb->packet_id);
|
||||
+ DPRINTF("get interface %d id %"PRIu64"\n", interface, p->id);
|
||||
|
||||
get_alt.interface = interface;
|
||||
- usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id,
|
||||
- &get_alt);
|
||||
+ usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
}
|
||||
@@ -731,7 +718,6 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
{
|
||||
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||
struct usb_redir_control_packet_header control_packet;
|
||||
- AsyncURB *aurb;
|
||||
|
||||
/* Special cases for certain standard device requests */
|
||||
switch (request) {
|
||||
@@ -749,13 +735,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
return usbredir_get_interface(dev, p, index);
|
||||
}
|
||||
|
||||
- /* "Normal" ctrl requests */
|
||||
- aurb = async_alloc(dev, p);
|
||||
-
|
||||
- /* Note request is (bRequestType << 8) | bRequest */
|
||||
- DPRINTF("ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %u\n",
|
||||
- request >> 8, request & 0xff, value, index, length,
|
||||
- aurb->packet_id);
|
||||
+ /* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */
|
||||
+ DPRINTF(
|
||||
+ "ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n",
|
||||
+ request >> 8, request & 0xff, value, index, length, p->id);
|
||||
|
||||
control_packet.request = request & 0xFF;
|
||||
control_packet.requesttype = request >> 8;
|
||||
@@ -765,11 +748,11 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
control_packet.length = length;
|
||||
|
||||
if (control_packet.requesttype & USB_DIR_IN) {
|
||||
- usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
|
||||
+ usbredirparser_send_control_packet(dev->parser, p->id,
|
||||
&control_packet, NULL, 0);
|
||||
} else {
|
||||
usbredir_log_data(dev, "ctrl data out:", data, length);
|
||||
- usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
|
||||
+ usbredirparser_send_control_packet(dev->parser, p->id,
|
||||
&control_packet, data, length);
|
||||
}
|
||||
usbredirparser_do_write(dev->parser);
|
||||
@@ -941,7 +924,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->asyncq);
|
||||
+ QTAILQ_INIT(&dev->cancelled);
|
||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||
QTAILQ_INIT(&dev->endpoint[i].bufpq);
|
||||
}
|
||||
@@ -959,11 +942,12 @@ static int usbredir_initfn(USBDevice *udev)
|
||||
|
||||
static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
|
||||
{
|
||||
- AsyncURB *aurb, *next_aurb;
|
||||
+ Cancelled *c, *next_c;
|
||||
int i;
|
||||
|
||||
- QTAILQ_FOREACH_SAFE(aurb, &dev->asyncq, next, next_aurb) {
|
||||
- async_free(dev, aurb);
|
||||
+ QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) {
|
||||
+ QTAILQ_REMOVE(&dev->cancelled, c, next);
|
||||
+ g_free(c);
|
||||
}
|
||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||
usbredir_free_bufpq(dev, I2EP(i));
|
||||
@@ -1229,33 +1213,28 @@ static void usbredir_configuration_status(void *priv, uint32_t id,
|
||||
struct usb_redir_configuration_status_header *config_status)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
- AsyncURB *aurb;
|
||||
+ USBPacket *p;
|
||||
int len = 0;
|
||||
|
||||
DPRINTF("set config status %d config %d id %u\n", config_status->status,
|
||||
config_status->configuration, id);
|
||||
|
||||
- aurb = async_find(dev, id);
|
||||
- if (!aurb) {
|
||||
- return;
|
||||
- }
|
||||
- if (aurb->packet) {
|
||||
+ p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
+ if (p) {
|
||||
if (dev->dev.setup_buf[0] & USB_DIR_IN) {
|
||||
dev->dev.data_buf[0] = config_status->configuration;
|
||||
len = 1;
|
||||
}
|
||||
- aurb->packet->result =
|
||||
- usbredir_handle_status(dev, config_status->status, len);
|
||||
- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
|
||||
+ p->result = usbredir_handle_status(dev, config_status->status, len);
|
||||
+ usb_generic_async_ctrl_complete(&dev->dev, p);
|
||||
}
|
||||
- async_free(dev, aurb);
|
||||
}
|
||||
|
||||
static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||
struct usb_redir_alt_setting_status_header *alt_setting_status)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
- AsyncURB *aurb;
|
||||
+ USBPacket *p;
|
||||
int len = 0;
|
||||
|
||||
DPRINTF("alt status %d intf %d alt %d id: %u\n",
|
||||
@@ -1263,20 +1242,16 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||
alt_setting_status->interface,
|
||||
alt_setting_status->alt, id);
|
||||
|
||||
- aurb = async_find(dev, id);
|
||||
- if (!aurb) {
|
||||
- return;
|
||||
- }
|
||||
- if (aurb->packet) {
|
||||
+ p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
+ if (p) {
|
||||
if (dev->dev.setup_buf[0] & USB_DIR_IN) {
|
||||
dev->dev.data_buf[0] = alt_setting_status->alt;
|
||||
len = 1;
|
||||
}
|
||||
- aurb->packet->result =
|
||||
+ p->result =
|
||||
usbredir_handle_status(dev, alt_setting_status->status, len);
|
||||
- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
|
||||
+ usb_generic_async_ctrl_complete(&dev->dev, p);
|
||||
}
|
||||
- async_free(dev, aurb);
|
||||
}
|
||||
|
||||
static void usbredir_iso_stream_status(void *priv, uint32_t id,
|
||||
@@ -1331,19 +1306,14 @@ static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
uint8_t *data, int data_len)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
+ USBPacket *p;
|
||||
int len = control_packet->length;
|
||||
- AsyncURB *aurb;
|
||||
|
||||
DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status,
|
||||
len, id);
|
||||
|
||||
- aurb = async_find(dev, id);
|
||||
- if (!aurb) {
|
||||
- free(data);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (aurb->packet) {
|
||||
+ p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
+ if (p) {
|
||||
len = usbredir_handle_status(dev, control_packet->status, len);
|
||||
if (len > 0) {
|
||||
usbredir_log_data(dev, "ctrl data in:", data, data_len);
|
||||
@@ -1355,10 +1325,9 @@ static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
len = USB_RET_STALL;
|
||||
}
|
||||
}
|
||||
- aurb->packet->result = len;
|
||||
- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
|
||||
+ p->result = len;
|
||||
+ usb_generic_async_ctrl_complete(&dev->dev, p);
|
||||
}
|
||||
- async_free(dev, aurb);
|
||||
free(data);
|
||||
}
|
||||
|
||||
@@ -1369,33 +1338,27 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
|
||||
USBRedirDevice *dev = priv;
|
||||
uint8_t ep = bulk_packet->endpoint;
|
||||
int len = bulk_packet->length;
|
||||
- AsyncURB *aurb;
|
||||
+ USBPacket *p;
|
||||
|
||||
DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status,
|
||||
ep, len, id);
|
||||
|
||||
- aurb = async_find(dev, id);
|
||||
- if (!aurb) {
|
||||
- free(data);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (aurb->packet) {
|
||||
+ p = usbredir_find_packet_by_id(dev, ep, id);
|
||||
+ if (p) {
|
||||
len = usbredir_handle_status(dev, bulk_packet->status, len);
|
||||
if (len > 0) {
|
||||
usbredir_log_data(dev, "bulk data in:", data, data_len);
|
||||
- if (data_len <= aurb->packet->iov.size) {
|
||||
- usb_packet_copy(aurb->packet, data, data_len);
|
||||
+ if (data_len <= p->iov.size) {
|
||||
+ usb_packet_copy(p, data, data_len);
|
||||
} else {
|
||||
ERROR("bulk buffer too small (%d > %zd)\n", data_len,
|
||||
- aurb->packet->iov.size);
|
||||
+ p->iov.size);
|
||||
len = USB_RET_STALL;
|
||||
}
|
||||
}
|
||||
- aurb->packet->result = len;
|
||||
- usb_packet_complete(&dev->dev, aurb->packet);
|
||||
+ p->result = len;
|
||||
+ usb_packet_complete(&dev->dev, p);
|
||||
}
|
||||
- async_free(dev, aurb);
|
||||
free(data);
|
||||
}
|
||||
|
||||
@@ -1453,17 +1416,12 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
|
||||
} else {
|
||||
int len = interrupt_packet->length;
|
||||
|
||||
- AsyncURB *aurb = async_find(dev, id);
|
||||
- if (!aurb) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (aurb->packet) {
|
||||
- aurb->packet->result = usbredir_handle_status(dev,
|
||||
+ USBPacket *p = usbredir_find_packet_by_id(dev, ep, id);
|
||||
+ if (p) {
|
||||
+ p->result = usbredir_handle_status(dev,
|
||||
interrupt_packet->status, len);
|
||||
- usb_packet_complete(&dev->dev, aurb->packet);
|
||||
+ usb_packet_complete(&dev->dev, p);
|
||||
}
|
||||
- async_free(dev, aurb);
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,34 @@
|
||||
From bd0bc4416beb7ecef0baf2424250c07b9ef15fb6 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 11:33:47 +0200
|
||||
Subject: [PATCH 323/366] usb-redir: Return babble when getting more bulk data
|
||||
then requested
|
||||
|
||||
Babble is the appropriate error in this case (rather then signalling a stall).
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 1ce994c..60b8f3e 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -1351,9 +1351,9 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
|
||||
if (data_len <= p->iov.size) {
|
||||
usb_packet_copy(p, data, data_len);
|
||||
} else {
|
||||
- ERROR("bulk buffer too small (%d > %zd)\n", data_len,
|
||||
- p->iov.size);
|
||||
- len = USB_RET_STALL;
|
||||
+ ERROR("bulk got more data then requested (%d > %zd)\n",
|
||||
+ data_len, p->iov.size);
|
||||
+ len = USB_RET_BABBLE;
|
||||
}
|
||||
}
|
||||
p->result = len;
|
||||
--
|
||||
1.7.12
|
||||
|
232
0324-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch
Normal file
232
0324-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch
Normal file
@ -0,0 +1,232 @@
|
||||
From 5ea5581f88d2e4bba876c2ee2544cf3641a64eca Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Fri, 31 Aug 2012 13:41:38 +0200
|
||||
Subject: [PATCH 324/366] usb-redir: Convert to new libusbredirparser 0.5 API
|
||||
|
||||
This gives us support for 64 bit ids which is needed for using XHCI with
|
||||
the new hcd generated ids.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
configure | 2 +-
|
||||
hw/usb/redirect.c | 62 +++++++++++++++++++++++++++----------------------------
|
||||
2 files changed, 32 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/configure b/configure
|
||||
index 0bfef84..25c406f 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -2765,7 +2765,7 @@ fi
|
||||
|
||||
# check for usbredirparser for usb network redirection support
|
||||
if test "$usb_redir" != "no" ; then
|
||||
- if $pkg_config --atleast-version=0.3.4 libusbredirparser >/dev/null 2>&1 ; then
|
||||
+ if $pkg_config --atleast-version=0.5 libusbredirparser >/dev/null 2>&1 ; then
|
||||
usb_redir="yes"
|
||||
usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
|
||||
usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 60b8f3e..789ef51 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -107,27 +107,27 @@ static void usbredir_interface_info(void *priv,
|
||||
struct usb_redir_interface_info_header *interface_info);
|
||||
static void usbredir_ep_info(void *priv,
|
||||
struct usb_redir_ep_info_header *ep_info);
|
||||
-static void usbredir_configuration_status(void *priv, uint32_t id,
|
||||
+static void usbredir_configuration_status(void *priv, uint64_t id,
|
||||
struct usb_redir_configuration_status_header *configuration_status);
|
||||
-static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||
+static void usbredir_alt_setting_status(void *priv, uint64_t id,
|
||||
struct usb_redir_alt_setting_status_header *alt_setting_status);
|
||||
-static void usbredir_iso_stream_status(void *priv, uint32_t id,
|
||||
+static void usbredir_iso_stream_status(void *priv, uint64_t id,
|
||||
struct usb_redir_iso_stream_status_header *iso_stream_status);
|
||||
-static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
|
||||
+static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
|
||||
struct usb_redir_interrupt_receiving_status_header
|
||||
*interrupt_receiving_status);
|
||||
-static void usbredir_bulk_streams_status(void *priv, uint32_t id,
|
||||
+static void usbredir_bulk_streams_status(void *priv, uint64_t id,
|
||||
struct usb_redir_bulk_streams_status_header *bulk_streams_status);
|
||||
-static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
+static void usbredir_control_packet(void *priv, uint64_t id,
|
||||
struct usb_redir_control_packet_header *control_packet,
|
||||
uint8_t *data, int data_len);
|
||||
-static void usbredir_bulk_packet(void *priv, uint32_t id,
|
||||
+static void usbredir_bulk_packet(void *priv, uint64_t id,
|
||||
struct usb_redir_bulk_packet_header *bulk_packet,
|
||||
uint8_t *data, int data_len);
|
||||
-static void usbredir_iso_packet(void *priv, uint32_t id,
|
||||
+static void usbredir_iso_packet(void *priv, uint64_t id,
|
||||
struct usb_redir_iso_packet_header *iso_packet,
|
||||
uint8_t *data, int data_len);
|
||||
-static void usbredir_interrupt_packet(void *priv, uint32_t id,
|
||||
+static void usbredir_interrupt_packet(void *priv, uint64_t id,
|
||||
struct usb_redir_interrupt_packet_header *interrupt_header,
|
||||
uint8_t *data, int data_len);
|
||||
|
||||
@@ -815,6 +815,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev)
|
||||
|
||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
|
||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
|
||||
+ usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
|
||||
usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
}
|
||||
@@ -1209,15 +1210,15 @@ static void usbredir_ep_info(void *priv,
|
||||
}
|
||||
}
|
||||
|
||||
-static void usbredir_configuration_status(void *priv, uint32_t id,
|
||||
+static void usbredir_configuration_status(void *priv, uint64_t id,
|
||||
struct usb_redir_configuration_status_header *config_status)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
USBPacket *p;
|
||||
int len = 0;
|
||||
|
||||
- DPRINTF("set config status %d config %d id %u\n", config_status->status,
|
||||
- config_status->configuration, id);
|
||||
+ DPRINTF("set config status %d config %d id %"PRIu64"\n",
|
||||
+ config_status->status, config_status->configuration, id);
|
||||
|
||||
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
if (p) {
|
||||
@@ -1230,16 +1231,15 @@ static void usbredir_configuration_status(void *priv, uint32_t id,
|
||||
}
|
||||
}
|
||||
|
||||
-static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||
+static void usbredir_alt_setting_status(void *priv, uint64_t id,
|
||||
struct usb_redir_alt_setting_status_header *alt_setting_status)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
USBPacket *p;
|
||||
int len = 0;
|
||||
|
||||
- DPRINTF("alt status %d intf %d alt %d id: %u\n",
|
||||
- alt_setting_status->status,
|
||||
- alt_setting_status->interface,
|
||||
+ DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n",
|
||||
+ alt_setting_status->status, alt_setting_status->interface,
|
||||
alt_setting_status->alt, id);
|
||||
|
||||
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
@@ -1254,13 +1254,13 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||
}
|
||||
}
|
||||
|
||||
-static void usbredir_iso_stream_status(void *priv, uint32_t id,
|
||||
+static void usbredir_iso_stream_status(void *priv, uint64_t id,
|
||||
struct usb_redir_iso_stream_status_header *iso_stream_status)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
uint8_t ep = iso_stream_status->endpoint;
|
||||
|
||||
- DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status,
|
||||
+ DPRINTF("iso status %d ep %02X id %"PRIu64"\n", iso_stream_status->status,
|
||||
ep, id);
|
||||
|
||||
if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) {
|
||||
@@ -1274,14 +1274,14 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id,
|
||||
}
|
||||
}
|
||||
|
||||
-static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
|
||||
+static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
|
||||
struct usb_redir_interrupt_receiving_status_header
|
||||
*interrupt_receiving_status)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
uint8_t ep = interrupt_receiving_status->endpoint;
|
||||
|
||||
- DPRINTF("interrupt recv status %d ep %02X id %u\n",
|
||||
+ DPRINTF("interrupt recv status %d ep %02X id %"PRIu64"\n",
|
||||
interrupt_receiving_status->status, ep, id);
|
||||
|
||||
if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) {
|
||||
@@ -1296,12 +1296,12 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
|
||||
}
|
||||
}
|
||||
|
||||
-static void usbredir_bulk_streams_status(void *priv, uint32_t id,
|
||||
+static void usbredir_bulk_streams_status(void *priv, uint64_t id,
|
||||
struct usb_redir_bulk_streams_status_header *bulk_streams_status)
|
||||
{
|
||||
}
|
||||
|
||||
-static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
+static void usbredir_control_packet(void *priv, uint64_t id,
|
||||
struct usb_redir_control_packet_header *control_packet,
|
||||
uint8_t *data, int data_len)
|
||||
{
|
||||
@@ -1309,7 +1309,7 @@ static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
USBPacket *p;
|
||||
int len = control_packet->length;
|
||||
|
||||
- DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status,
|
||||
+ DPRINTF("ctrl-in status %d len %d id %"PRIu64"\n", control_packet->status,
|
||||
len, id);
|
||||
|
||||
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
@@ -1331,7 +1331,7 @@ static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
free(data);
|
||||
}
|
||||
|
||||
-static void usbredir_bulk_packet(void *priv, uint32_t id,
|
||||
+static void usbredir_bulk_packet(void *priv, uint64_t id,
|
||||
struct usb_redir_bulk_packet_header *bulk_packet,
|
||||
uint8_t *data, int data_len)
|
||||
{
|
||||
@@ -1340,8 +1340,8 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
|
||||
int len = bulk_packet->length;
|
||||
USBPacket *p;
|
||||
|
||||
- DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status,
|
||||
- ep, len, id);
|
||||
+ DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n",
|
||||
+ bulk_packet->status, ep, len, id);
|
||||
|
||||
p = usbredir_find_packet_by_id(dev, ep, id);
|
||||
if (p) {
|
||||
@@ -1362,15 +1362,15 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
|
||||
free(data);
|
||||
}
|
||||
|
||||
-static void usbredir_iso_packet(void *priv, uint32_t id,
|
||||
+static void usbredir_iso_packet(void *priv, uint64_t id,
|
||||
struct usb_redir_iso_packet_header *iso_packet,
|
||||
uint8_t *data, int data_len)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
uint8_t ep = iso_packet->endpoint;
|
||||
|
||||
- DPRINTF2("iso-in status %d ep %02X len %d id %u\n", iso_packet->status, ep,
|
||||
- data_len, id);
|
||||
+ DPRINTF2("iso-in status %d ep %02X len %d id %"PRIu64"\n",
|
||||
+ iso_packet->status, ep, data_len, id);
|
||||
|
||||
if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) {
|
||||
ERROR("received iso packet for non iso endpoint %02X\n", ep);
|
||||
@@ -1388,14 +1388,14 @@ static void usbredir_iso_packet(void *priv, uint32_t id,
|
||||
bufp_alloc(dev, data, data_len, iso_packet->status, ep);
|
||||
}
|
||||
|
||||
-static void usbredir_interrupt_packet(void *priv, uint32_t id,
|
||||
+static void usbredir_interrupt_packet(void *priv, uint64_t id,
|
||||
struct usb_redir_interrupt_packet_header *interrupt_packet,
|
||||
uint8_t *data, int data_len)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
uint8_t ep = interrupt_packet->endpoint;
|
||||
|
||||
- DPRINTF("interrupt-in status %d ep %02X len %d id %u\n",
|
||||
+ DPRINTF("interrupt-in status %d ep %02X len %d id %"PRIu64"\n",
|
||||
interrupt_packet->status, ep, data_len, id);
|
||||
|
||||
if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) {
|
||||
--
|
||||
1.7.12
|
||||
|
39
0325-usb-redir-Set-ep-max_packet_size-if-available.patch
Normal file
39
0325-usb-redir-Set-ep-max_packet_size-if-available.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From 7c936f9e6b07f4468f49886b4e785e4120a08e11 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 11:49:07 +0200
|
||||
Subject: [PATCH 325/366] usb-redir: Set ep max_packet_size if available
|
||||
|
||||
This is needed for usb-redir to work properly with the xhci emulation.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 789ef51..ac8bfd2 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -815,6 +815,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev)
|
||||
|
||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
|
||||
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);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
@@ -1207,6 +1208,10 @@ static void usbredir_ep_info(void *priv,
|
||||
i & 0x0f);
|
||||
usb_ep->type = dev->endpoint[i].type;
|
||||
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];
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,59 @@
|
||||
From 4ba71f5871be4d92f36097bc431fc303e1e42a7a Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 11:53:28 +0200
|
||||
Subject: [PATCH 326/366] usb-redir: Add a usbredir_reject_device helper
|
||||
function
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 21 +++++++++++----------
|
||||
1 file changed, 11 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index ac8bfd2..357f307 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -821,16 +821,21 @@ static void usbredir_chardev_open(USBRedirDevice *dev)
|
||||
usbredirparser_do_write(dev->parser);
|
||||
}
|
||||
|
||||
+static void usbredir_reject_device(USBRedirDevice *dev)
|
||||
+{
|
||||
+ usbredir_device_disconnect(dev);
|
||||
+ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
|
||||
+ usbredirparser_send_filter_reject(dev->parser);
|
||||
+ usbredirparser_do_write(dev->parser);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void usbredir_do_attach(void *opaque)
|
||||
{
|
||||
USBRedirDevice *dev = opaque;
|
||||
|
||||
if (usb_device_attach(&dev->dev) != 0) {
|
||||
- usbredir_device_disconnect(dev);
|
||||
- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
|
||||
- usbredirparser_send_filter_reject(dev->parser);
|
||||
- usbredirparser_do_write(dev->parser);
|
||||
- }
|
||||
+ usbredir_reject_device(dev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,11 +1018,7 @@ static int usbredir_check_filter(USBRedirDevice *dev)
|
||||
return 0;
|
||||
|
||||
error:
|
||||
- usbredir_device_disconnect(dev);
|
||||
- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
|
||||
- usbredirparser_send_filter_reject(dev->parser);
|
||||
- usbredirparser_do_write(dev->parser);
|
||||
- }
|
||||
+ usbredir_reject_device(dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
@ -0,0 +1,43 @@
|
||||
From af1ecda005c043dd8186725ae7a93ea66ebfe96f Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 12:04:49 +0200
|
||||
Subject: [PATCH 327/366] usb-redir: Ensure our peer has the necessary caps
|
||||
when redirecting to XHCI
|
||||
|
||||
In order for redirection to work properly when redirecting to an emulated
|
||||
XHCI controller, the usb-redir-host must support both
|
||||
usb_redir_cap_ep_info_max_packet_size and usb_redir_cap_64bits_ids,
|
||||
reject any devices redirected to an XHCI controller when these are not
|
||||
supported.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 357f307..5b0f834 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -834,6 +834,17 @@ static void usbredir_do_attach(void *opaque)
|
||||
{
|
||||
USBRedirDevice *dev = opaque;
|
||||
|
||||
+ /* In order to work properly with XHCI controllers we need these caps */
|
||||
+ if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !(
|
||||
+ usbredirparser_peer_has_cap(dev->parser,
|
||||
+ usb_redir_cap_ep_info_max_packet_size) &&
|
||||
+ usbredirparser_peer_has_cap(dev->parser,
|
||||
+ usb_redir_cap_64bits_ids))) {
|
||||
+ ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n");
|
||||
+ usbredir_reject_device(dev);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (usb_device_attach(&dev->dev) != 0) {
|
||||
usbredir_reject_device(dev);
|
||||
}
|
||||
--
|
||||
1.7.12
|
||||
|
28
0328-usb-redir-Enable-pipelining-for-bulk-endpoints.patch
Normal file
28
0328-usb-redir-Enable-pipelining-for-bulk-endpoints.patch
Normal file
@ -0,0 +1,28 @@
|
||||
From 30b6793253b39f347e1f74791118403451b9886c Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Mon, 3 Sep 2012 13:44:04 +0200
|
||||
Subject: [PATCH 328/366] usb-redir: Enable pipelining for bulk endpoints
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 5b0f834..9cbcddb 100644
|
||||
--- a/hw/usb/redirect.c
|
||||
+++ b/hw/usb/redirect.c
|
||||
@@ -1224,6 +1224,9 @@ static void usbredir_ep_info(void *priv,
|
||||
usb_redir_cap_ep_info_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
|
||||
|
30
0329-Better-name-usb-braille-device.patch
Normal file
30
0329-Better-name-usb-braille-device.patch
Normal file
@ -0,0 +1,30 @@
|
||||
From f83e26f01f1489af484f69bdeb2d01d4896de6ec Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
Date: Thu, 23 Aug 2012 09:59:27 +0200
|
||||
Subject: [PATCH 329/366] Better name usb braille device
|
||||
|
||||
Windows users need to know that they have to use the Baum driver to make
|
||||
the qemu braille device work.
|
||||
|
||||
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/dev-serial.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
|
||||
index 8fc9bdd..0ddfab6 100644
|
||||
--- a/hw/usb/dev-serial.c
|
||||
+++ b/hw/usb/dev-serial.c
|
||||
@@ -113,7 +113,7 @@ enum {
|
||||
static const USBDescStrings desc_strings = {
|
||||
[STR_MANUFACTURER] = "QEMU",
|
||||
[STR_PRODUCT_SERIAL] = "QEMU USB SERIAL",
|
||||
- [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE",
|
||||
+ [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE",
|
||||
[STR_SERIALNUMBER] = "1",
|
||||
};
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
29
0330-usb-audio-fix-usb-version.patch
Normal file
29
0330-usb-audio-fix-usb-version.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From 77824f2b7aba75a3f31a996634dc836fe26ee2c5 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 16:43:34 +0200
|
||||
Subject: [PATCH 330/366] usb-audio: fix usb version
|
||||
|
||||
usb-audio is a full speed (1.1) device,
|
||||
but bcdUSB claims it is usb 2.0. Fix it.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/dev-audio.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
|
||||
index 79b75fb..2594c78 100644
|
||||
--- a/hw/usb/dev-audio.c
|
||||
+++ b/hw/usb/dev-audio.c
|
||||
@@ -217,7 +217,7 @@ static const USBDescIface desc_iface[] = {
|
||||
};
|
||||
|
||||
static const USBDescDevice desc_device = {
|
||||
- .bcdUSB = 0x0200,
|
||||
+ .bcdUSB = 0x0100,
|
||||
.bMaxPacketSize0 = 64,
|
||||
.bNumConfigurations = 1,
|
||||
.confs = (USBDescConfig[]) {
|
||||
--
|
||||
1.7.12
|
||||
|
324
0331-xhci-rip-out-background-transfer-code.patch
Normal file
324
0331-xhci-rip-out-background-transfer-code.patch
Normal file
@ -0,0 +1,324 @@
|
||||
From f019cdb4b17a0615e897ddac37f2ffa8866a4979 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 17 Aug 2012 14:05:21 +0200
|
||||
Subject: [PATCH 331/366] xhci: rip out background transfer code
|
||||
|
||||
original xhci code (the one which used libusb directly) used to use
|
||||
'background transfers' for iso streams. In upstream qemu the iso
|
||||
stream buffering is handled by usb-host & usb-redir, so we will
|
||||
never ever need this. It has been left in as reference, but is dead
|
||||
code anyway. Rip it out.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 223 +-----------------------------------------------------
|
||||
1 file changed, 4 insertions(+), 219 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 3eb27fa..c0a2476 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -45,8 +45,6 @@
|
||||
#define MAXPORTS (USB2_PORTS+USB3_PORTS)
|
||||
|
||||
#define TD_QUEUE 24
|
||||
-#define BG_XFERS 8
|
||||
-#define BG_PKTS 8
|
||||
|
||||
/* Very pessimistic, let's hope it's enough for all cases */
|
||||
#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
|
||||
@@ -311,13 +309,11 @@ typedef struct XHCITransfer {
|
||||
bool running_retry;
|
||||
bool cancelled;
|
||||
bool complete;
|
||||
- bool backgrounded;
|
||||
unsigned int iso_pkts;
|
||||
unsigned int slotid;
|
||||
unsigned int epid;
|
||||
bool in_xfer;
|
||||
bool iso_xfer;
|
||||
- bool bg_xfer;
|
||||
|
||||
unsigned int trb_count;
|
||||
unsigned int trb_alloced;
|
||||
@@ -340,14 +336,9 @@ typedef struct XHCIEPContext {
|
||||
unsigned int comp_xfer;
|
||||
XHCITransfer transfers[TD_QUEUE];
|
||||
XHCITransfer *retry;
|
||||
- bool bg_running;
|
||||
- bool bg_updating;
|
||||
- unsigned int next_bg;
|
||||
- XHCITransfer bg_transfers[BG_XFERS];
|
||||
EPType type;
|
||||
dma_addr_t pctx;
|
||||
unsigned int max_psize;
|
||||
- bool has_bg;
|
||||
uint32_t state;
|
||||
} XHCIEPContext;
|
||||
|
||||
@@ -866,10 +857,6 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
|
||||
epctx->pctx = pctx;
|
||||
epctx->max_psize = ctx[1]>>16;
|
||||
epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
|
||||
- epctx->has_bg = false;
|
||||
- if (epctx->type == ET_ISO_IN) {
|
||||
- epctx->has_bg = true;
|
||||
- }
|
||||
DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
|
||||
epid/2, epid%2, epctx->max_psize);
|
||||
for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
|
||||
@@ -916,9 +903,6 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
|
||||
t->running_retry = 0;
|
||||
epctx->retry = NULL;
|
||||
}
|
||||
- if (t->backgrounded) {
|
||||
- t->backgrounded = 0;
|
||||
- }
|
||||
if (t->trbs) {
|
||||
g_free(t->trbs);
|
||||
}
|
||||
@@ -932,25 +916,6 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
|
||||
t->data_length = t->data_alloced = 0;
|
||||
xferi = (xferi + 1) % TD_QUEUE;
|
||||
}
|
||||
- if (epctx->has_bg) {
|
||||
- xferi = epctx->next_bg;
|
||||
- for (i = 0; i < BG_XFERS; i++) {
|
||||
- XHCITransfer *t = &epctx->bg_transfers[xferi];
|
||||
- if (t->running_async) {
|
||||
- usb_cancel_packet(&t->packet);
|
||||
- t->running_async = 0;
|
||||
- t->cancelled = 1;
|
||||
- DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i);
|
||||
- killed++;
|
||||
- }
|
||||
- if (t->data) {
|
||||
- g_free(t->data);
|
||||
- }
|
||||
-
|
||||
- t->data = NULL;
|
||||
- xferi = (xferi + 1) % BG_XFERS;
|
||||
- }
|
||||
- }
|
||||
return killed;
|
||||
}
|
||||
|
||||
@@ -1231,160 +1196,6 @@ static void xhci_stall_ep(XHCITransfer *xfer)
|
||||
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
|
||||
XHCIEPContext *epctx);
|
||||
|
||||
-static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx)
|
||||
-{
|
||||
- if (epctx->bg_updating) {
|
||||
- return;
|
||||
- }
|
||||
- DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx);
|
||||
- assert(epctx->has_bg);
|
||||
- DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg);
|
||||
- epctx->bg_updating = 1;
|
||||
- while (epctx->transfers[epctx->comp_xfer].backgrounded &&
|
||||
- epctx->bg_transfers[epctx->next_bg].complete) {
|
||||
- XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer];
|
||||
- XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg];
|
||||
-#if 0
|
||||
- DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n",
|
||||
- epctx->comp_xfer, epctx->next_bg, bg->cur_pkt,
|
||||
- bg->usbxfer->iso_packet_desc[bg->cur_pkt].status
|
||||
- );
|
||||
-#endif
|
||||
- assert(epctx->type == ET_ISO_IN);
|
||||
- assert(bg->iso_xfer);
|
||||
- assert(bg->in_xfer);
|
||||
- uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize;
|
||||
-#if 0
|
||||
- int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length;
|
||||
- fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status);
|
||||
-#else
|
||||
- int len = 0;
|
||||
- FIXME();
|
||||
-#endif
|
||||
- fg->complete = 1;
|
||||
- fg->backgrounded = 0;
|
||||
-
|
||||
- if (fg->status == CC_STALL_ERROR) {
|
||||
- xhci_stall_ep(fg);
|
||||
- }
|
||||
-
|
||||
- xhci_xfer_data(fg, p, len, 1, 0, 1);
|
||||
-
|
||||
- epctx->comp_xfer++;
|
||||
- if (epctx->comp_xfer == TD_QUEUE) {
|
||||
- epctx->comp_xfer = 0;
|
||||
- }
|
||||
- DPRINTF("next fg xfer: %d\n", epctx->comp_xfer);
|
||||
- bg->cur_pkt++;
|
||||
- if (bg->cur_pkt == bg->pkts) {
|
||||
- bg->complete = 0;
|
||||
- if (xhci_submit(xhci, bg, epctx) < 0) {
|
||||
- fprintf(stderr, "xhci: bg resubmit failed\n");
|
||||
- }
|
||||
- epctx->next_bg++;
|
||||
- if (epctx->next_bg == BG_XFERS) {
|
||||
- epctx->next_bg = 0;
|
||||
- }
|
||||
- DPRINTF("next bg xfer: %d\n", epctx->next_bg);
|
||||
-
|
||||
- xhci_kick_ep(xhci, fg->slotid, fg->epid);
|
||||
- }
|
||||
- }
|
||||
- epctx->bg_updating = 0;
|
||||
-}
|
||||
-
|
||||
-#if 0
|
||||
-static void xhci_xfer_cb(struct libusb_transfer *transfer)
|
||||
-{
|
||||
- XHCIState *xhci;
|
||||
- XHCITransfer *xfer;
|
||||
-
|
||||
- xfer = (XHCITransfer *)transfer->user_data;
|
||||
- xhci = xfer->xhci;
|
||||
-
|
||||
- DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid,
|
||||
- xfer->epid, transfer->status);
|
||||
-
|
||||
- assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS);
|
||||
- assert(xfer->epid >= 1 && xfer->epid <= 31);
|
||||
-
|
||||
- if (xfer->cancelled) {
|
||||
- DPRINTF("xhci: transfer cancelled, not reporting anything\n");
|
||||
- xfer->running = 0;
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- XHCIEPContext *epctx;
|
||||
- XHCISlot *slot;
|
||||
- slot = &xhci->slots[xfer->slotid-1];
|
||||
- assert(slot->eps[xfer->epid-1]);
|
||||
- epctx = slot->eps[xfer->epid-1];
|
||||
-
|
||||
- if (xfer->bg_xfer) {
|
||||
- DPRINTF("xhci: background transfer, updating\n");
|
||||
- xfer->complete = 1;
|
||||
- xfer->running = 0;
|
||||
- xhci_bg_update(xhci, epctx);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (xfer->iso_xfer) {
|
||||
- transfer->status = transfer->iso_packet_desc[0].status;
|
||||
- transfer->actual_length = transfer->iso_packet_desc[0].actual_length;
|
||||
- }
|
||||
-
|
||||
- xfer->status = libusb_to_ccode(transfer->status);
|
||||
-
|
||||
- xfer->complete = 1;
|
||||
- xfer->running = 0;
|
||||
-
|
||||
- if (transfer->status == LIBUSB_TRANSFER_STALL)
|
||||
- xhci_stall_ep(xhci, epctx, xfer);
|
||||
-
|
||||
- DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length);
|
||||
-
|
||||
- if (xfer->in_xfer) {
|
||||
- if (xfer->epid == 1) {
|
||||
- xhci_xfer_data(xhci, xfer, xfer->data + 8,
|
||||
- transfer->actual_length, 1, 0, 1);
|
||||
- } else {
|
||||
- xhci_xfer_data(xhci, xfer, xfer->data,
|
||||
- transfer->actual_length, 1, 0, 1);
|
||||
- }
|
||||
- } else {
|
||||
- xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1);
|
||||
- }
|
||||
-
|
||||
- xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
|
||||
-}
|
||||
-
|
||||
-static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer,
|
||||
- uint8_t bmRequestType, uint8_t bRequest,
|
||||
- uint16_t wValue, uint16_t wIndex, uint16_t wLength)
|
||||
-{
|
||||
- uint16_t type_req = (bmRequestType << 8) | bRequest;
|
||||
-
|
||||
- switch (type_req) {
|
||||
- case 0x0000 | USB_REQ_SET_CONFIGURATION:
|
||||
- DPRINTF("xhci: HLE switch configuration\n");
|
||||
- return xhci_switch_config(xhci, xfer->slotid, wValue) == 0;
|
||||
- case 0x0100 | USB_REQ_SET_INTERFACE:
|
||||
- DPRINTF("xhci: HLE set interface altsetting\n");
|
||||
- return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0;
|
||||
- case 0x0200 | USB_REQ_CLEAR_FEATURE:
|
||||
- if (wValue == 0) { // endpoint halt
|
||||
- DPRINTF("xhci: HLE clear halt\n");
|
||||
- return xhci_clear_halt(xhci, xfer->slotid, wIndex);
|
||||
- }
|
||||
- case 0x0000 | USB_REQ_SET_ADDRESS:
|
||||
- fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n");
|
||||
- return 0;
|
||||
- default:
|
||||
- return 0;
|
||||
- }
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
|
||||
{
|
||||
USBEndpoint *ep;
|
||||
@@ -1559,9 +1370,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
|
||||
xfer->data_alloced = xfer->data_length;
|
||||
}
|
||||
if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
|
||||
- if (!xfer->bg_xfer) {
|
||||
- xfer->pkts = 1;
|
||||
- }
|
||||
+ xfer->pkts = 1;
|
||||
} else {
|
||||
xfer->pkts = 0;
|
||||
}
|
||||
@@ -1620,32 +1429,8 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext
|
||||
|
||||
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length);
|
||||
|
||||
- if (!epctx->has_bg) {
|
||||
- xfer->data_length = length;
|
||||
- xfer->backgrounded = 0;
|
||||
- return xhci_submit(xhci, xfer, epctx);
|
||||
- } else {
|
||||
- if (!epctx->bg_running) {
|
||||
- for (i = 0; i < BG_XFERS; i++) {
|
||||
- XHCITransfer *t = &epctx->bg_transfers[i];
|
||||
- t->xhci = xhci;
|
||||
- t->epid = xfer->epid;
|
||||
- t->slotid = xfer->slotid;
|
||||
- t->pkts = BG_PKTS;
|
||||
- t->pktsize = epctx->max_psize;
|
||||
- t->data_length = t->pkts * t->pktsize;
|
||||
- t->bg_xfer = 1;
|
||||
- if (xhci_submit(xhci, t, epctx) < 0) {
|
||||
- fprintf(stderr, "xhci: bg submit failed\n");
|
||||
- return -1;
|
||||
- }
|
||||
- }
|
||||
- epctx->bg_running = 1;
|
||||
- }
|
||||
- xfer->backgrounded = 1;
|
||||
- xhci_bg_update(xhci, epctx);
|
||||
- return 0;
|
||||
- }
|
||||
+ xfer->data_length = length;
|
||||
+ return xhci_submit(xhci, xfer, epctx);
|
||||
}
|
||||
|
||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
|
||||
@@ -1695,7 +1480,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
|
||||
|
||||
while (1) {
|
||||
XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
|
||||
- if (xfer->running_async || xfer->running_retry || xfer->backgrounded) {
|
||||
+ if (xfer->running_async || xfer->running_retry) {
|
||||
break;
|
||||
}
|
||||
length = xhci_ring_chain_length(xhci, &epctx->ring);
|
||||
--
|
||||
1.7.12
|
||||
|
372
0332-xhci-drop-buffering.patch
Normal file
372
0332-xhci-drop-buffering.patch
Normal file
@ -0,0 +1,372 @@
|
||||
From ad14386b3f1ccd445afd30d30a343cb9fcf6c0a7 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 17 Aug 2012 11:04:36 +0200
|
||||
Subject: [PATCH 332/366] xhci: drop buffering
|
||||
|
||||
This patch splits the xhci_xfer_data function into three.
|
||||
The xhci_xfer_data function used to do does two things:
|
||||
|
||||
(1) copy transfer data between guest memory and a temporary buffer.
|
||||
(2) report transfer results to the guest using events.
|
||||
|
||||
Now we three functions to handle this:
|
||||
|
||||
(1) xhci_xfer_map creates a scatter list for the transfer and
|
||||
uses that (instead of the temporary buffer) to build a
|
||||
USBPacket.
|
||||
(2) xhci_xfer_unmap undoes the mapping.
|
||||
(3) xhci_xfer_report sends out events.
|
||||
|
||||
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.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 183 +++++++++++++++++++++---------------------------------
|
||||
trace-events | 2 +-
|
||||
2 files changed, 72 insertions(+), 113 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index c0a2476..c858b6d 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -305,6 +305,7 @@ typedef struct XHCIState XHCIState;
|
||||
typedef struct XHCITransfer {
|
||||
XHCIState *xhci;
|
||||
USBPacket packet;
|
||||
+ QEMUSGList sgl;
|
||||
bool running_async;
|
||||
bool running_retry;
|
||||
bool cancelled;
|
||||
@@ -319,10 +320,6 @@ typedef struct XHCITransfer {
|
||||
unsigned int trb_alloced;
|
||||
XHCITRB *trbs;
|
||||
|
||||
- unsigned int data_length;
|
||||
- unsigned int data_alloced;
|
||||
- uint8_t *data;
|
||||
-
|
||||
TRBCCode status;
|
||||
|
||||
unsigned int pkts;
|
||||
@@ -906,14 +903,9 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
|
||||
if (t->trbs) {
|
||||
g_free(t->trbs);
|
||||
}
|
||||
- if (t->data) {
|
||||
- g_free(t->data);
|
||||
- }
|
||||
|
||||
t->trbs = NULL;
|
||||
- t->data = NULL;
|
||||
t->trb_count = t->trb_alloced = 0;
|
||||
- t->data_length = t->data_alloced = 0;
|
||||
xferi = (xferi + 1) % TD_QUEUE;
|
||||
}
|
||||
return killed;
|
||||
@@ -1072,24 +1064,13 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
|
||||
return CC_SUCCESS;
|
||||
}
|
||||
|
||||
-static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
||||
- unsigned int length, bool in_xfer, bool out_xfer,
|
||||
- bool report)
|
||||
+static int xhci_xfer_map(XHCITransfer *xfer)
|
||||
{
|
||||
- int i;
|
||||
- uint32_t edtla = 0;
|
||||
- unsigned int transferred = 0;
|
||||
- unsigned int left = length;
|
||||
- bool reported = 0;
|
||||
- bool shortpkt = 0;
|
||||
- XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
|
||||
+ int in_xfer = (xfer->packet.pid == USB_TOKEN_IN);
|
||||
XHCIState *xhci = xfer->xhci;
|
||||
+ int i;
|
||||
|
||||
- DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n",
|
||||
- length, in_xfer, out_xfer, report);
|
||||
-
|
||||
- assert(!(in_xfer && out_xfer));
|
||||
-
|
||||
+ pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count);
|
||||
for (i = 0; i < xfer->trb_count; i++) {
|
||||
XHCITRB *trb = &xfer->trbs[i];
|
||||
dma_addr_t addr;
|
||||
@@ -1099,54 +1080,70 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
||||
case TR_DATA:
|
||||
if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
|
||||
fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
|
||||
- xhci_die(xhci);
|
||||
- return transferred;
|
||||
+ goto err;
|
||||
}
|
||||
/* fallthrough */
|
||||
case TR_NORMAL:
|
||||
case TR_ISOCH:
|
||||
addr = xhci_mask64(trb->parameter);
|
||||
chunk = trb->status & 0x1ffff;
|
||||
+ if (trb->control & TRB_TR_IDT) {
|
||||
+ if (chunk > 8 || in_xfer) {
|
||||
+ fprintf(stderr, "xhci: invalid immediate data TRB\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ qemu_sglist_add(&xfer->sgl, trb->addr, chunk);
|
||||
+ } else {
|
||||
+ qemu_sglist_add(&xfer->sgl, addr, chunk);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ usb_packet_map(&xfer->packet, &xfer->sgl);
|
||||
+ return 0;
|
||||
+
|
||||
+err:
|
||||
+ qemu_sglist_destroy(&xfer->sgl);
|
||||
+ xhci_die(xhci);
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+static void xhci_xfer_unmap(XHCITransfer *xfer)
|
||||
+{
|
||||
+ usb_packet_unmap(&xfer->packet, &xfer->sgl);
|
||||
+ qemu_sglist_destroy(&xfer->sgl);
|
||||
+}
|
||||
+
|
||||
+static void xhci_xfer_report(XHCITransfer *xfer)
|
||||
+{
|
||||
+ uint32_t edtla = 0;
|
||||
+ unsigned int left;
|
||||
+ bool reported = 0;
|
||||
+ bool shortpkt = 0;
|
||||
+ XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
|
||||
+ XHCIState *xhci = xfer->xhci;
|
||||
+ int i;
|
||||
+
|
||||
+ left = xfer->packet.result < 0 ? 0 : xfer->packet.result;
|
||||
+
|
||||
+ for (i = 0; i < xfer->trb_count; i++) {
|
||||
+ XHCITRB *trb = &xfer->trbs[i];
|
||||
+ unsigned int chunk = 0;
|
||||
+
|
||||
+ switch (TRB_TYPE(*trb)) {
|
||||
+ case TR_DATA:
|
||||
+ case TR_NORMAL:
|
||||
+ case TR_ISOCH:
|
||||
+ chunk = trb->status & 0x1ffff;
|
||||
if (chunk > left) {
|
||||
chunk = left;
|
||||
- shortpkt = 1;
|
||||
- }
|
||||
- if (in_xfer || out_xfer) {
|
||||
- if (trb->control & TRB_TR_IDT) {
|
||||
- uint64_t idata;
|
||||
- if (chunk > 8 || in_xfer) {
|
||||
- fprintf(stderr, "xhci: invalid immediate data TRB\n");
|
||||
- xhci_die(xhci);
|
||||
- return transferred;
|
||||
- }
|
||||
- idata = le64_to_cpu(trb->parameter);
|
||||
- memcpy(data, &idata, chunk);
|
||||
- } else {
|
||||
- DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at "
|
||||
- DMA_ADDR_FMT "\n", in_xfer, chunk, addr);
|
||||
- if (in_xfer) {
|
||||
- pci_dma_write(&xhci->pci_dev, addr, data, chunk);
|
||||
- } else {
|
||||
- pci_dma_read(&xhci->pci_dev, addr, data, chunk);
|
||||
- }
|
||||
-#ifdef DEBUG_DATA
|
||||
- unsigned int count = chunk;
|
||||
- int i;
|
||||
- if (count > 16) {
|
||||
- count = 16;
|
||||
- }
|
||||
- DPRINTF(" ::");
|
||||
- for (i = 0; i < count; i++) {
|
||||
- DPRINTF(" %02x", data[i]);
|
||||
- }
|
||||
- DPRINTF("\n");
|
||||
-#endif
|
||||
+ if (xfer->status == CC_SUCCESS) {
|
||||
+ shortpkt = 1;
|
||||
}
|
||||
}
|
||||
left -= chunk;
|
||||
- data += chunk;
|
||||
edtla += chunk;
|
||||
- transferred += chunk;
|
||||
break;
|
||||
case TR_STATUS:
|
||||
reported = 0;
|
||||
@@ -1154,8 +1151,9 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
||||
break;
|
||||
}
|
||||
|
||||
- if (report && !reported && (trb->control & TRB_TR_IOC ||
|
||||
- (shortpkt && (trb->control & TRB_TR_ISP)))) {
|
||||
+ if (!reported && ((trb->control & TRB_TR_IOC) ||
|
||||
+ (shortpkt && (trb->control & TRB_TR_ISP)) ||
|
||||
+ (xfer->status != CC_SUCCESS))) {
|
||||
event.slotid = xfer->slotid;
|
||||
event.epid = xfer->epid;
|
||||
event.length = (trb->status & 0x1ffff) - chunk;
|
||||
@@ -1175,9 +1173,11 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
||||
}
|
||||
xhci_event(xhci, &event);
|
||||
reported = 1;
|
||||
+ if (xfer->status != CC_SUCCESS) {
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
- return transferred;
|
||||
}
|
||||
|
||||
static void xhci_stall_ep(XHCITransfer *xfer)
|
||||
@@ -1204,7 +1204,7 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
|
||||
dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
|
||||
ep = usb_ep_get(dev, dir, xfer->epid >> 1);
|
||||
usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr);
|
||||
- usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
|
||||
+ xhci_xfer_map(xfer);
|
||||
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
|
||||
xfer->packet.pid, dev->addr, ep->nr);
|
||||
return 0;
|
||||
@@ -1230,12 +1230,13 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
|
||||
xfer->running_async = 0;
|
||||
xfer->running_retry = 0;
|
||||
xfer->complete = 1;
|
||||
+ xhci_xfer_unmap(xfer);
|
||||
}
|
||||
|
||||
if (ret >= 0) {
|
||||
- xfer->status = CC_SUCCESS;
|
||||
- xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1);
|
||||
trace_usb_xhci_xfer_success(xfer, ret);
|
||||
+ xfer->status = CC_SUCCESS;
|
||||
+ xhci_xfer_report(xfer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1244,12 +1245,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
|
||||
switch (ret) {
|
||||
case USB_RET_NODEV:
|
||||
xfer->status = CC_USB_TRANSACTION_ERROR;
|
||||
- xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
|
||||
+ xhci_xfer_report(xfer);
|
||||
xhci_stall_ep(xfer);
|
||||
break;
|
||||
case USB_RET_STALL:
|
||||
xfer->status = CC_STALL_ERROR;
|
||||
- xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
|
||||
+ xhci_xfer_report(xfer);
|
||||
xhci_stall_ep(xfer);
|
||||
break;
|
||||
default:
|
||||
@@ -1279,8 +1280,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
|
||||
trb_setup = &xfer->trbs[0];
|
||||
trb_status = &xfer->trbs[xfer->trb_count-1];
|
||||
|
||||
- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid,
|
||||
- trb_setup->parameter >> 48);
|
||||
+ trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
|
||||
|
||||
/* 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;
|
||||
|
||||
- if (xfer->data && xfer->data_alloced < wLength) {
|
||||
- xfer->data_alloced = 0;
|
||||
- g_free(xfer->data);
|
||||
- xfer->data = NULL;
|
||||
- }
|
||||
- if (!xfer->data) {
|
||||
- DPRINTF("xhci: alloc %d bytes data\n", wLength);
|
||||
- xfer->data = g_malloc(wLength+1);
|
||||
- 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)
|
||||
|
||||
xhci_setup_packet(xfer, dev);
|
||||
xfer->packet.parameter = trb_setup->parameter;
|
||||
- if (!xfer->in_xfer) {
|
||||
- xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
|
||||
- }
|
||||
|
||||
ret = usb_handle_packet(dev, &xfer->packet);
|
||||
|
||||
@@ -1359,16 +1344,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
|
||||
|
||||
xfer->in_xfer = epctx->type>>2;
|
||||
|
||||
- if (xfer->data && xfer->data_alloced < xfer->data_length) {
|
||||
- xfer->data_alloced = 0;
|
||||
- g_free(xfer->data);
|
||||
- xfer->data = NULL;
|
||||
- }
|
||||
- if (!xfer->data && xfer->data_length) {
|
||||
- DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length);
|
||||
- xfer->data = g_malloc(xfer->data_length);
|
||||
- xfer->data_alloced = xfer->data_length;
|
||||
- }
|
||||
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
|
||||
return -1;
|
||||
}
|
||||
|
||||
- if (!xfer->in_xfer) {
|
||||
- xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0);
|
||||
- }
|
||||
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
|
||||
|
||||
static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
|
||||
{
|
||||
- int i;
|
||||
- unsigned int length = 0;
|
||||
- XHCITRB *trb;
|
||||
-
|
||||
- for (i = 0; i < xfer->trb_count; i++) {
|
||||
- trb = &xfer->trbs[i];
|
||||
- if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) {
|
||||
- length += trb->status & 0x1ffff;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length);
|
||||
-
|
||||
- xfer->data_length = length;
|
||||
+ trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
|
||||
return xhci_submit(xhci, xfer, epctx);
|
||||
}
|
||||
|
||||
diff --git a/trace-events b/trace-events
|
||||
index 10bc04e..c83d65e 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -326,7 +326,7 @@ usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
-usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t length) "%p: slotid %d, epid %d, length %d"
|
||||
+usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d"
|
||||
usb_xhci_xfer_async(void *xfer) "%p"
|
||||
usb_xhci_xfer_nak(void *xfer) "%p"
|
||||
usb_xhci_xfer_retry(void *xfer) "%p"
|
||||
--
|
||||
1.7.12
|
||||
|
155
0333-xhci-move-device-lookup-into-xhci_setup_packet.patch
Normal file
155
0333-xhci-move-device-lookup-into-xhci_setup_packet.patch
Normal file
@ -0,0 +1,155 @@
|
||||
From 76d49f5c5abc30f33f5b9288df68d53dba9e10f0 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 24 Aug 2012 14:21:39 +0200
|
||||
Subject: [PATCH 333/366] xhci: move device lookup into xhci_setup_packet
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 74 ++++++++++++++++++++++++++++---------------------------
|
||||
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
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -1196,13 +1196,38 @@ static void xhci_stall_ep(XHCITransfer *xfer)
|
||||
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
|
||||
XHCIEPContext *epctx);
|
||||
|
||||
-static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
|
||||
+static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr)
|
||||
{
|
||||
+ if (!(port->portsc & PORTSC_PED)) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ return usb_find_device(&port->port, addr);
|
||||
+}
|
||||
+
|
||||
+static int xhci_setup_packet(XHCITransfer *xfer)
|
||||
+{
|
||||
+ XHCIState *xhci = xfer->xhci;
|
||||
+ XHCIPort *port;
|
||||
+ USBDevice *dev;
|
||||
USBEndpoint *ep;
|
||||
int dir;
|
||||
|
||||
dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
|
||||
- ep = usb_ep_get(dev, dir, xfer->epid >> 1);
|
||||
+
|
||||
+ if (xfer->packet.ep) {
|
||||
+ ep = xfer->packet.ep;
|
||||
+ dev = ep->dev;
|
||||
+ } else {
|
||||
+ port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
|
||||
+ dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
|
||||
+ if (!dev) {
|
||||
+ fprintf(stderr, "xhci: slot %d port %d has no device\n",
|
||||
+ xfer->slotid, xhci->slots[xfer->slotid-1].port);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ ep = usb_ep_get(dev, dir, xfer->epid >> 1);
|
||||
+ }
|
||||
+
|
||||
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)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr)
|
||||
-{
|
||||
- if (!(port->portsc & PORTSC_PED)) {
|
||||
- return NULL;
|
||||
- }
|
||||
- return usb_find_device(&port->port, addr);
|
||||
-}
|
||||
-
|
||||
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;
|
||||
|
||||
trb_setup = &xfer->trbs[0];
|
||||
@@ -1311,21 +1326,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);
|
||||
- if (!dev) {
|
||||
- fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
|
||||
- xhci->slots[xfer->slotid-1].port);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
xfer->in_xfer = bmRequestType & USB_DIR_IN;
|
||||
xfer->iso_xfer = false;
|
||||
|
||||
- xhci_setup_packet(xfer, dev);
|
||||
+ if (xhci_setup_packet(xfer) < 0) {
|
||||
+ return -1;
|
||||
+ }
|
||||
xfer->packet.parameter = trb_setup->parameter;
|
||||
|
||||
- ret = usb_handle_packet(dev, &xfer->packet);
|
||||
+ ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
|
||||
|
||||
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)
|
||||
|
||||
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
|
||||
{
|
||||
- XHCIPort *port;
|
||||
- USBDevice *dev;
|
||||
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
|
||||
xfer->pkts = 0;
|
||||
}
|
||||
|
||||
- port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
|
||||
- dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
|
||||
- if (!dev) {
|
||||
- fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
|
||||
- xhci->slots[xfer->slotid-1].port);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- xhci_setup_packet(xfer, dev);
|
||||
-
|
||||
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
|
||||
return -1;
|
||||
}
|
||||
|
||||
- ret = usb_handle_packet(dev, &xfer->packet);
|
||||
+ if (xhci_setup_packet(xfer) < 0) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+ ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
|
||||
|
||||
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
|
||||
|
||||
trace_usb_xhci_xfer_retry(xfer);
|
||||
assert(xfer->running_retry);
|
||||
- xhci_setup_packet(xfer, xfer->packet.ep->dev);
|
||||
+ if (xhci_setup_packet(xfer) < 0) {
|
||||
+ return;
|
||||
+ }
|
||||
result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
|
||||
if (result == USB_RET_NAK) {
|
||||
return;
|
||||
--
|
||||
1.7.12
|
||||
|
142
0334-xhci-implement-mfindex.patch
Normal file
142
0334-xhci-implement-mfindex.patch
Normal file
@ -0,0 +1,142 @@
|
||||
From 6a1c694cd009fb7e4656e1c9a18756da6f89be14 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 21 Aug 2012 12:32:58 +0200
|
||||
Subject: [PATCH 334/366] xhci: implement mfindex
|
||||
|
||||
Implement mfindex register and mfindex wrap event.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++-------
|
||||
1 file changed, 46 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 303e1ac..9077cb3 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -380,8 +380,6 @@ struct XHCIState {
|
||||
XHCISlot slots[MAXSLOTS];
|
||||
|
||||
/* Runtime Registers */
|
||||
- uint32_t mfindex;
|
||||
- /* note: we only support one interrupter */
|
||||
uint32_t iman;
|
||||
uint32_t imod;
|
||||
uint32_t erstsz;
|
||||
@@ -390,6 +388,9 @@ struct XHCIState {
|
||||
uint32_t erdp_low;
|
||||
uint32_t erdp_high;
|
||||
|
||||
+ int64_t mfindex_start;
|
||||
+ QEMUTimer *mfwrap_timer;
|
||||
+
|
||||
dma_addr_t er_start;
|
||||
uint32_t er_size;
|
||||
bool er_pcs;
|
||||
@@ -410,6 +411,11 @@ typedef struct XHCIEvRingSeg {
|
||||
uint32_t rsvd;
|
||||
} XHCIEvRingSeg;
|
||||
|
||||
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||
+ unsigned int epid);
|
||||
+static void xhci_event(XHCIState *xhci, XHCIEvent *event);
|
||||
+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event);
|
||||
+
|
||||
static const char *TRBType_names[] = {
|
||||
[TRB_RESERVED] = "TRB_RESERVED",
|
||||
[TR_NORMAL] = "TR_NORMAL",
|
||||
@@ -462,8 +468,36 @@ static const char *trb_name(XHCITRB *trb)
|
||||
ARRAY_SIZE(TRBType_names));
|
||||
}
|
||||
|
||||
-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||
- unsigned int epid);
|
||||
+static uint64_t xhci_mfindex_get(XHCIState *xhci)
|
||||
+{
|
||||
+ int64_t now = qemu_get_clock_ns(vm_clock);
|
||||
+ return (now - xhci->mfindex_start) / 125000;
|
||||
+}
|
||||
+
|
||||
+static void xhci_mfwrap_update(XHCIState *xhci)
|
||||
+{
|
||||
+ const uint32_t bits = USBCMD_RS | USBCMD_EWE;
|
||||
+ uint32_t mfindex, left;
|
||||
+ int64_t now;
|
||||
+
|
||||
+ if ((xhci->usbcmd & bits) == bits) {
|
||||
+ now = qemu_get_clock_ns(vm_clock);
|
||||
+ mfindex = ((now - xhci->mfindex_start) / 125000) & 0x3fff;
|
||||
+ left = 0x4000 - mfindex;
|
||||
+ qemu_mod_timer(xhci->mfwrap_timer, now + left * 125000);
|
||||
+ } else {
|
||||
+ qemu_del_timer(xhci->mfwrap_timer);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void xhci_mfwrap_timer(void *opaque)
|
||||
+{
|
||||
+ XHCIState *xhci = opaque;
|
||||
+ XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS };
|
||||
+
|
||||
+ xhci_event(xhci, &wrap);
|
||||
+ xhci_mfwrap_update(xhci);
|
||||
+}
|
||||
|
||||
static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high)
|
||||
{
|
||||
@@ -793,6 +827,7 @@ static void xhci_run(XHCIState *xhci)
|
||||
{
|
||||
trace_usb_xhci_run();
|
||||
xhci->usbsts &= ~USBSTS_HCH;
|
||||
+ xhci->mfindex_start = qemu_get_clock_ns(vm_clock);
|
||||
}
|
||||
|
||||
static void xhci_stop(XHCIState *xhci)
|
||||
@@ -2050,7 +2085,6 @@ static void xhci_reset(DeviceState *dev)
|
||||
xhci_update_port(xhci, xhci->ports + i, 0);
|
||||
}
|
||||
|
||||
- xhci->mfindex = 0;
|
||||
xhci->iman = 0;
|
||||
xhci->imod = 0;
|
||||
xhci->erstsz = 0;
|
||||
@@ -2064,6 +2098,9 @@ static void xhci_reset(DeviceState *dev)
|
||||
xhci->er_full = 0;
|
||||
xhci->ev_buffer_put = 0;
|
||||
xhci->ev_buffer_get = 0;
|
||||
+
|
||||
+ xhci->mfindex_start = qemu_get_clock_ns(vm_clock);
|
||||
+ xhci_mfwrap_update(xhci);
|
||||
}
|
||||
|
||||
static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
|
||||
@@ -2266,6 +2303,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
xhci_stop(xhci);
|
||||
}
|
||||
xhci->usbcmd = val & 0xc0f;
|
||||
+ xhci_mfwrap_update(xhci);
|
||||
if (val & USBCMD_HCRST) {
|
||||
xhci_reset(&xhci->pci_dev.qdev);
|
||||
}
|
||||
@@ -2317,8 +2355,7 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
|
||||
switch (reg) {
|
||||
case 0x00: /* MFINDEX */
|
||||
- fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n");
|
||||
- ret = xhci->mfindex;
|
||||
+ ret = xhci_mfindex_get(xhci) & 0x3fff;
|
||||
break;
|
||||
case 0x20: /* IMAN */
|
||||
ret = xhci->iman;
|
||||
@@ -2618,6 +2655,8 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
|
||||
|
||||
usb_xhci_init(xhci, &dev->qdev);
|
||||
|
||||
+ xhci->mfwrap_timer = qemu_new_timer_ns(vm_clock, xhci_mfwrap_timer, xhci);
|
||||
+
|
||||
xhci->irq = xhci->pci_dev.irq[0];
|
||||
|
||||
memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci,
|
||||
--
|
||||
1.7.12
|
||||
|
238
0335-xhci-iso-xfer-support.patch
Normal file
238
0335-xhci-iso-xfer-support.patch
Normal file
@ -0,0 +1,238 @@
|
||||
From 9f7a9361a816479ca109e1747e45d40135fad3b0 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 24 Aug 2012 14:13:08 +0200
|
||||
Subject: [PATCH 335/366] xhci: iso xfer support
|
||||
|
||||
Add support for iso transfers.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 101 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 9077cb3..3c61bb8 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -325,9 +325,15 @@ typedef struct XHCITransfer {
|
||||
unsigned int pkts;
|
||||
unsigned int pktsize;
|
||||
unsigned int cur_pkt;
|
||||
+
|
||||
+ uint64_t mfindex_kick;
|
||||
} XHCITransfer;
|
||||
|
||||
typedef struct XHCIEPContext {
|
||||
+ XHCIState *xhci;
|
||||
+ unsigned int slotid;
|
||||
+ unsigned int epid;
|
||||
+
|
||||
XHCIRing ring;
|
||||
unsigned int next_xfer;
|
||||
unsigned int comp_xfer;
|
||||
@@ -337,6 +343,11 @@ typedef struct XHCIEPContext {
|
||||
dma_addr_t pctx;
|
||||
unsigned int max_psize;
|
||||
uint32_t state;
|
||||
+
|
||||
+ /* iso xfer scheduling */
|
||||
+ unsigned int interval;
|
||||
+ int64_t mfindex_last;
|
||||
+ QEMUTimer *kick_timer;
|
||||
} XHCIEPContext;
|
||||
|
||||
typedef struct XHCISlot {
|
||||
@@ -856,6 +867,12 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
|
||||
epctx->state = state;
|
||||
}
|
||||
|
||||
+static void xhci_ep_kick_timer(void *opaque)
|
||||
+{
|
||||
+ XHCIEPContext *epctx = opaque;
|
||||
+ xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid);
|
||||
+}
|
||||
+
|
||||
static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
|
||||
unsigned int epid, dma_addr_t pctx,
|
||||
uint32_t *ctx)
|
||||
@@ -877,6 +894,9 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
|
||||
|
||||
epctx = g_malloc(sizeof(XHCIEPContext));
|
||||
memset(epctx, 0, sizeof(XHCIEPContext));
|
||||
+ epctx->xhci = xhci;
|
||||
+ epctx->slotid = slotid;
|
||||
+ epctx->epid = epid;
|
||||
|
||||
slot->eps[epid-1] = epctx;
|
||||
|
||||
@@ -895,6 +915,10 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
|
||||
usb_packet_init(&epctx->transfers[i].packet);
|
||||
}
|
||||
|
||||
+ epctx->interval = 1 << (ctx[0] >> 16) & 0xff;
|
||||
+ epctx->mfindex_last = 0;
|
||||
+ epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx);
|
||||
+
|
||||
epctx->state = EP_RUNNING;
|
||||
ctx[0] &= ~EP_STATE_MASK;
|
||||
ctx[0] |= EP_RUNNING;
|
||||
@@ -934,6 +958,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
|
||||
if (t->running_retry) {
|
||||
t->running_retry = 0;
|
||||
epctx->retry = NULL;
|
||||
+ qemu_del_timer(epctx->kick_timer);
|
||||
}
|
||||
if (t->trbs) {
|
||||
g_free(t->trbs);
|
||||
@@ -969,6 +994,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
|
||||
|
||||
xhci_set_ep_state(xhci, epctx, EP_DISABLED);
|
||||
|
||||
+ qemu_free_timer(epctx->kick_timer);
|
||||
g_free(epctx);
|
||||
slot->eps[epid-1] = NULL;
|
||||
|
||||
@@ -1378,29 +1404,70 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void xhci_calc_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
|
||||
+ XHCIEPContext *epctx, uint64_t mfindex)
|
||||
+{
|
||||
+ if (xfer->trbs[0].control & TRB_TR_SIA) {
|
||||
+ uint64_t asap = ((mfindex + epctx->interval - 1) &
|
||||
+ ~(epctx->interval-1));
|
||||
+ if (asap >= epctx->mfindex_last &&
|
||||
+ asap <= epctx->mfindex_last + epctx->interval * 4) {
|
||||
+ xfer->mfindex_kick = epctx->mfindex_last + epctx->interval;
|
||||
+ } else {
|
||||
+ xfer->mfindex_kick = asap;
|
||||
+ }
|
||||
+ } else {
|
||||
+ xfer->mfindex_kick = (xfer->trbs[0].control >> TRB_TR_FRAMEID_SHIFT)
|
||||
+ & TRB_TR_FRAMEID_MASK;
|
||||
+ xfer->mfindex_kick |= mfindex & ~0x3fff;
|
||||
+ if (xfer->mfindex_kick < mfindex) {
|
||||
+ xfer->mfindex_kick += 0x4000;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void xhci_check_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
|
||||
+ XHCIEPContext *epctx, uint64_t mfindex)
|
||||
+{
|
||||
+ if (xfer->mfindex_kick > mfindex) {
|
||||
+ qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock) +
|
||||
+ (xfer->mfindex_kick - mfindex) * 125000);
|
||||
+ xfer->running_retry = 1;
|
||||
+ } else {
|
||||
+ epctx->mfindex_last = xfer->mfindex_kick;
|
||||
+ qemu_del_timer(epctx->kick_timer);
|
||||
+ xfer->running_retry = 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
|
||||
{
|
||||
+ uint64_t mfindex;
|
||||
int ret;
|
||||
|
||||
DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
|
||||
|
||||
xfer->in_xfer = epctx->type>>2;
|
||||
|
||||
- if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
|
||||
- xfer->pkts = 1;
|
||||
- } else {
|
||||
- xfer->pkts = 0;
|
||||
- }
|
||||
-
|
||||
switch(epctx->type) {
|
||||
case ET_INTR_OUT:
|
||||
case ET_INTR_IN:
|
||||
case ET_BULK_OUT:
|
||||
case ET_BULK_IN:
|
||||
+ xfer->pkts = 0;
|
||||
+ xfer->iso_xfer = false;
|
||||
break;
|
||||
case ET_ISO_OUT:
|
||||
case ET_ISO_IN:
|
||||
- FIXME();
|
||||
+ xfer->pkts = 1;
|
||||
+ xfer->iso_xfer = true;
|
||||
+ mfindex = xhci_mfindex_get(xhci);
|
||||
+ xhci_calc_iso_kick(xhci, xfer, epctx, mfindex);
|
||||
+ xhci_check_iso_kick(xhci, xfer, epctx, mfindex);
|
||||
+ if (xfer->running_retry) {
|
||||
+ return -1;
|
||||
+ }
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "xhci: unknown or unhandled EP "
|
||||
@@ -1430,6 +1497,7 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext
|
||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
|
||||
{
|
||||
XHCIEPContext *epctx;
|
||||
+ uint64_t mfindex;
|
||||
int length;
|
||||
int i;
|
||||
|
||||
@@ -1449,20 +1517,35 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
|
||||
}
|
||||
|
||||
if (epctx->retry) {
|
||||
- /* retry nak'ed transfer */
|
||||
XHCITransfer *xfer = epctx->retry;
|
||||
int result;
|
||||
|
||||
trace_usb_xhci_xfer_retry(xfer);
|
||||
assert(xfer->running_retry);
|
||||
- if (xhci_setup_packet(xfer) < 0) {
|
||||
- return;
|
||||
- }
|
||||
- result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
|
||||
- if (result == USB_RET_NAK) {
|
||||
- return;
|
||||
+ if (xfer->iso_xfer) {
|
||||
+ /* retry delayed iso transfer */
|
||||
+ mfindex = xhci_mfindex_get(xhci);
|
||||
+ xhci_check_iso_kick(xhci, xfer, epctx, mfindex);
|
||||
+ if (xfer->running_retry) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (xhci_setup_packet(xfer) < 0) {
|
||||
+ return;
|
||||
+ }
|
||||
+ result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
|
||||
+ assert(result != USB_RET_NAK);
|
||||
+ xhci_complete_packet(xfer, result);
|
||||
+ } else {
|
||||
+ /* retry nak'ed transfer */
|
||||
+ if (xhci_setup_packet(xfer) < 0) {
|
||||
+ return;
|
||||
+ }
|
||||
+ result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
|
||||
+ if (result == USB_RET_NAK) {
|
||||
+ return;
|
||||
+ }
|
||||
+ xhci_complete_packet(xfer, result);
|
||||
}
|
||||
- xhci_complete_packet(xfer, result);
|
||||
assert(!xfer->running_retry);
|
||||
epctx->retry = NULL;
|
||||
}
|
||||
@@ -1514,7 +1597,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
|
||||
if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
|
||||
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
|
||||
} else {
|
||||
- fprintf(stderr, "xhci: error firing data transfer\n");
|
||||
+ if (!xfer->iso_xfer) {
|
||||
+ fprintf(stderr, "xhci: error firing data transfer\n");
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
100
0336-xhci-trace-cc-codes-in-cleartext.patch
Normal file
100
0336-xhci-trace-cc-codes-in-cleartext.patch
Normal file
@ -0,0 +1,100 @@
|
||||
From 530efbfebc3b33f6b109e52d57a25e9b7fe2b588 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Mon, 27 Aug 2012 16:09:20 +0200
|
||||
Subject: [PATCH 336/366] xhci: trace cc codes in cleartext
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
trace-events | 2 +-
|
||||
2 files changed, 48 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 3c61bb8..ab32a7b 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -465,6 +465,45 @@ static const char *TRBType_names[] = {
|
||||
[CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE",
|
||||
};
|
||||
|
||||
+static const char *TRBCCode_names[] = {
|
||||
+ [CC_INVALID] = "CC_INVALID",
|
||||
+ [CC_SUCCESS] = "CC_SUCCESS",
|
||||
+ [CC_DATA_BUFFER_ERROR] = "CC_DATA_BUFFER_ERROR",
|
||||
+ [CC_BABBLE_DETECTED] = "CC_BABBLE_DETECTED",
|
||||
+ [CC_USB_TRANSACTION_ERROR] = "CC_USB_TRANSACTION_ERROR",
|
||||
+ [CC_TRB_ERROR] = "CC_TRB_ERROR",
|
||||
+ [CC_STALL_ERROR] = "CC_STALL_ERROR",
|
||||
+ [CC_RESOURCE_ERROR] = "CC_RESOURCE_ERROR",
|
||||
+ [CC_BANDWIDTH_ERROR] = "CC_BANDWIDTH_ERROR",
|
||||
+ [CC_NO_SLOTS_ERROR] = "CC_NO_SLOTS_ERROR",
|
||||
+ [CC_INVALID_STREAM_TYPE_ERROR] = "CC_INVALID_STREAM_TYPE_ERROR",
|
||||
+ [CC_SLOT_NOT_ENABLED_ERROR] = "CC_SLOT_NOT_ENABLED_ERROR",
|
||||
+ [CC_EP_NOT_ENABLED_ERROR] = "CC_EP_NOT_ENABLED_ERROR",
|
||||
+ [CC_SHORT_PACKET] = "CC_SHORT_PACKET",
|
||||
+ [CC_RING_UNDERRUN] = "CC_RING_UNDERRUN",
|
||||
+ [CC_RING_OVERRUN] = "CC_RING_OVERRUN",
|
||||
+ [CC_VF_ER_FULL] = "CC_VF_ER_FULL",
|
||||
+ [CC_PARAMETER_ERROR] = "CC_PARAMETER_ERROR",
|
||||
+ [CC_BANDWIDTH_OVERRUN] = "CC_BANDWIDTH_OVERRUN",
|
||||
+ [CC_CONTEXT_STATE_ERROR] = "CC_CONTEXT_STATE_ERROR",
|
||||
+ [CC_NO_PING_RESPONSE_ERROR] = "CC_NO_PING_RESPONSE_ERROR",
|
||||
+ [CC_EVENT_RING_FULL_ERROR] = "CC_EVENT_RING_FULL_ERROR",
|
||||
+ [CC_INCOMPATIBLE_DEVICE_ERROR] = "CC_INCOMPATIBLE_DEVICE_ERROR",
|
||||
+ [CC_MISSED_SERVICE_ERROR] = "CC_MISSED_SERVICE_ERROR",
|
||||
+ [CC_COMMAND_RING_STOPPED] = "CC_COMMAND_RING_STOPPED",
|
||||
+ [CC_COMMAND_ABORTED] = "CC_COMMAND_ABORTED",
|
||||
+ [CC_STOPPED] = "CC_STOPPED",
|
||||
+ [CC_STOPPED_LENGTH_INVALID] = "CC_STOPPED_LENGTH_INVALID",
|
||||
+ [CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR]
|
||||
+ = "CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR",
|
||||
+ [CC_ISOCH_BUFFER_OVERRUN] = "CC_ISOCH_BUFFER_OVERRUN",
|
||||
+ [CC_EVENT_LOST_ERROR] = "CC_EVENT_LOST_ERROR",
|
||||
+ [CC_UNDEFINED_ERROR] = "CC_UNDEFINED_ERROR",
|
||||
+ [CC_INVALID_STREAM_ID_ERROR] = "CC_INVALID_STREAM_ID_ERROR",
|
||||
+ [CC_SECONDARY_BANDWIDTH_ERROR] = "CC_SECONDARY_BANDWIDTH_ERROR",
|
||||
+ [CC_SPLIT_TRANSACTION_ERROR] = "CC_SPLIT_TRANSACTION_ERROR",
|
||||
+};
|
||||
+
|
||||
static const char *lookup_name(uint32_t index, const char **list, uint32_t llen)
|
||||
{
|
||||
if (index >= llen || list[index] == NULL) {
|
||||
@@ -479,6 +518,12 @@ static const char *trb_name(XHCITRB *trb)
|
||||
ARRAY_SIZE(TRBType_names));
|
||||
}
|
||||
|
||||
+static const char *event_name(XHCIEvent *event)
|
||||
+{
|
||||
+ return lookup_name(event->ccode, TRBCCode_names,
|
||||
+ ARRAY_SIZE(TRBCCode_names));
|
||||
+}
|
||||
+
|
||||
static uint64_t xhci_mfindex_get(XHCIState *xhci)
|
||||
{
|
||||
int64_t now = qemu_get_clock_ns(vm_clock);
|
||||
@@ -574,7 +619,8 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
|
||||
ev_trb.control = cpu_to_le32(ev_trb.control);
|
||||
|
||||
trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb),
|
||||
- ev_trb.parameter, ev_trb.status, ev_trb.control);
|
||||
+ event_name(event), ev_trb.parameter,
|
||||
+ ev_trb.status, ev_trb.control);
|
||||
|
||||
addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
|
||||
pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE);
|
||||
diff --git a/trace-events b/trace-events
|
||||
index c83d65e..27d59cd 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -313,7 +313,7 @@ usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x"
|
||||
usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x"
|
||||
usb_xhci_irq_intx(uint32_t level) "level %d"
|
||||
usb_xhci_irq_msi(uint32_t nr) "nr %d"
|
||||
-usb_xhci_queue_event(uint32_t idx, const char *name, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
+usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
|
||||
usb_xhci_slot_disable(uint32_t slotid) "slotid %d"
|
||||
--
|
||||
1.7.12
|
||||
|
39
0337-xhci-add-trace_usb_xhci_ep_set_dequeue.patch
Normal file
39
0337-xhci-add-trace_usb_xhci_ep_set_dequeue.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From 53adf697ca70ee8298b6abeb05ebf5a0ebebdc1c Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Wed, 29 Aug 2012 12:54:59 +0200
|
||||
Subject: [PATCH 337/366] xhci: add trace_usb_xhci_ep_set_dequeue
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 2 +-
|
||||
trace-events | 1 +
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index ab32a7b..5cdaf76 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -1145,7 +1145,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
|
||||
return CC_TRB_ERROR;
|
||||
}
|
||||
|
||||
- DPRINTF("xhci_set_ep_dequeue(%d, %d, %016"PRIx64")\n", slotid, epid, pdequeue);
|
||||
+ trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue);
|
||||
dequeue = xhci_mask64(pdequeue);
|
||||
|
||||
slot = &xhci->slots[slotid-1];
|
||||
diff --git a/trace-events b/trace-events
|
||||
index 27d59cd..a894689 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -323,6 +323,7 @@ usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d"
|
||||
usb_xhci_slot_reset(uint32_t slotid) "slotid %d"
|
||||
usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
+usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint64_t param) "slotid %d, epid %d, ptr %016" PRIx64
|
||||
usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
|
||||
--
|
||||
1.7.12
|
||||
|
26
0338-xhci-fix-runtime-write-tracepoint.patch
Normal file
26
0338-xhci-fix-runtime-write-tracepoint.patch
Normal file
@ -0,0 +1,26 @@
|
||||
From 9c1e6303c5c86f20ed083a0ed9c829c08fd2ac06 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 12:42:32 +0200
|
||||
Subject: [PATCH 338/366] xhci: fix runtime write tracepoint
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 5cdaf76..e8d2372 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -2520,7 +2520,7 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
|
||||
static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
{
|
||||
- trace_usb_xhci_runtime_read(reg, val);
|
||||
+ trace_usb_xhci_runtime_write(reg, val);
|
||||
|
||||
switch (reg) {
|
||||
case 0x20: /* IMAN */
|
||||
--
|
||||
1.7.12
|
||||
|
63
0339-xhci-update-register-layout.patch
Normal file
63
0339-xhci-update-register-layout.patch
Normal file
@ -0,0 +1,63 @@
|
||||
From 56a4ea65ecc929a355b0cc243099d2e3a9862843 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 23 Aug 2012 13:26:25 +0200
|
||||
Subject: [PATCH 339/366] xhci: update register layout
|
||||
|
||||
Change the register layout to be a bit more sparse and also not depend
|
||||
on the number of ports. Useful when for making the number of ports
|
||||
runtime-configurable.
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 21 +++++++++++++--------
|
||||
1 file changed, 13 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index e8d2372..414b633 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -36,13 +36,12 @@
|
||||
#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
|
||||
__func__, __LINE__); abort(); } while (0)
|
||||
|
||||
-#define MAXSLOTS 8
|
||||
-#define MAXINTRS 1
|
||||
-
|
||||
#define USB2_PORTS 4
|
||||
#define USB3_PORTS 4
|
||||
|
||||
#define MAXPORTS (USB2_PORTS+USB3_PORTS)
|
||||
+#define MAXSLOTS MAXPORTS
|
||||
+#define MAXINTRS 1 /* MAXPORTS */
|
||||
|
||||
#define TD_QUEUE 24
|
||||
|
||||
@@ -53,16 +52,22 @@
|
||||
#define ER_FULL_HACK
|
||||
|
||||
#define LEN_CAP 0x40
|
||||
-#define OFF_OPER LEN_CAP
|
||||
#define LEN_OPER (0x400 + 0x10 * MAXPORTS)
|
||||
-#define OFF_RUNTIME ((OFF_OPER + LEN_OPER + 0x20) & ~0x1f)
|
||||
-#define LEN_RUNTIME (0x20 + MAXINTRS * 0x20)
|
||||
-#define OFF_DOORBELL (OFF_RUNTIME + LEN_RUNTIME)
|
||||
+#define LEN_RUNTIME ((MAXINTRS + 1) * 0x20)
|
||||
#define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20)
|
||||
|
||||
+#define OFF_OPER LEN_CAP
|
||||
+#define OFF_RUNTIME 0x1000
|
||||
+#define OFF_DOORBELL 0x2000
|
||||
/* must be power of 2 */
|
||||
-#define LEN_REGS 0x2000
|
||||
+#define LEN_REGS 0x4000
|
||||
|
||||
+#if (OFF_OPER + LEN_OPER) > OFF_RUNTIME
|
||||
+#error Increase OFF_RUNTIME
|
||||
+#endif
|
||||
+#if (OFF_RUNTIME + LEN_RUNTIME) > OFF_DOORBELL
|
||||
+#error Increase OFF_DOORBELL
|
||||
+#endif
|
||||
#if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS
|
||||
# error Increase LEN_REGS
|
||||
#endif
|
||||
--
|
||||
1.7.12
|
||||
|
352
0340-xhci-update-port-handling.patch
Normal file
352
0340-xhci-update-port-handling.patch
Normal file
@ -0,0 +1,352 @@
|
||||
From ed16ece865cb40c9ad8ddf28905c0af3ad80e118 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 13:38:01 +0200
|
||||
Subject: [PATCH 340/366] xhci: update port handling
|
||||
|
||||
This patch changes the way xhci ports are linked to USBPorts. The fixed
|
||||
1:1 relationship between xhci ports and USBPorts is gone. Now each
|
||||
USBPort represents a physical plug which has usually two xhci ports
|
||||
assigned: one usb2 and ond usb3 port. usb devices show up at one or the
|
||||
other, depending on whenever they support superspeed or not.
|
||||
|
||||
This patch also makes the number of usb2 and usb3 ports runtime
|
||||
configurable by adding 'p2' and 'p3' properties. It is allowed to
|
||||
have different numbers of usb2 and usb3 ports. Specifying p2=4,p3=2
|
||||
will give you an xhci adapter which supports all speeds on physical
|
||||
ports 1+2 and usb2 only on ports 3+4.
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 137 ++++++++++++++++++++++++++++++++++++++----------------
|
||||
1 file changed, 97 insertions(+), 40 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 414b633..e08312e 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -36,10 +36,10 @@
|
||||
#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
|
||||
__func__, __LINE__); abort(); } while (0)
|
||||
|
||||
-#define USB2_PORTS 4
|
||||
-#define USB3_PORTS 4
|
||||
+#define MAXPORTS_2 8
|
||||
+#define MAXPORTS_3 8
|
||||
|
||||
-#define MAXPORTS (USB2_PORTS+USB3_PORTS)
|
||||
+#define MAXPORTS (MAXPORTS_2+MAXPORTS_3)
|
||||
#define MAXSLOTS MAXPORTS
|
||||
#define MAXINTRS 1 /* MAXPORTS */
|
||||
|
||||
@@ -300,8 +300,10 @@ typedef struct XHCIRing {
|
||||
} XHCIRing;
|
||||
|
||||
typedef struct XHCIPort {
|
||||
- USBPort port;
|
||||
uint32_t portsc;
|
||||
+ uint32_t portnr;
|
||||
+ USBPort *uport;
|
||||
+ uint32_t speedmask;
|
||||
} XHCIPort;
|
||||
|
||||
struct XHCIState;
|
||||
@@ -379,9 +381,13 @@ struct XHCIState {
|
||||
qemu_irq irq;
|
||||
MemoryRegion mem;
|
||||
const char *name;
|
||||
- uint32_t msi;
|
||||
unsigned int devaddr;
|
||||
|
||||
+ /* properties */
|
||||
+ uint32_t numports_2;
|
||||
+ uint32_t numports_3;
|
||||
+ uint32_t msi;
|
||||
+
|
||||
/* Operational Registers */
|
||||
uint32_t usbcmd;
|
||||
uint32_t usbsts;
|
||||
@@ -392,8 +398,10 @@ struct XHCIState {
|
||||
uint32_t dcbaap_high;
|
||||
uint32_t config;
|
||||
|
||||
+ USBPort uports[MAX(MAXPORTS_2, MAXPORTS_3)];
|
||||
XHCIPort ports[MAXPORTS];
|
||||
XHCISlot slots[MAXSLOTS];
|
||||
+ uint32_t numports;
|
||||
|
||||
/* Runtime Registers */
|
||||
uint32_t iman;
|
||||
@@ -578,6 +586,28 @@ static inline dma_addr_t xhci_mask64(uint64_t addr)
|
||||
}
|
||||
}
|
||||
|
||||
+static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
|
||||
+{
|
||||
+ int index;
|
||||
+
|
||||
+ if (!uport->dev) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ switch (uport->dev->speed) {
|
||||
+ case USB_SPEED_LOW:
|
||||
+ case USB_SPEED_FULL:
|
||||
+ case USB_SPEED_HIGH:
|
||||
+ index = uport->index;
|
||||
+ break;
|
||||
+ case USB_SPEED_SUPER:
|
||||
+ index = uport->index + xhci->numports_2;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ return &xhci->ports[index];
|
||||
+}
|
||||
+
|
||||
static void xhci_irq_update(XHCIState *xhci)
|
||||
{
|
||||
int level = 0;
|
||||
@@ -1126,7 +1156,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
|
||||
ep |= 0x80;
|
||||
}
|
||||
|
||||
- dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev;
|
||||
+ dev = xhci->ports[xhci->slots[slotid-1].port-1].uport->dev;
|
||||
if (!dev) {
|
||||
return CC_USB_TRANSACTION_ERROR;
|
||||
}
|
||||
@@ -1313,7 +1343,7 @@ static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr)
|
||||
if (!(port->portsc & PORTSC_PED)) {
|
||||
return NULL;
|
||||
}
|
||||
- return usb_find_device(&port->port, addr);
|
||||
+ return usb_find_device(port->uport, addr);
|
||||
}
|
||||
|
||||
static int xhci_setup_packet(XHCITransfer *xfer)
|
||||
@@ -1736,9 +1766,9 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
|
||||
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
|
||||
|
||||
port = (slot_ctx[1]>>16) & 0xFF;
|
||||
- dev = xhci->ports[port-1].port.dev;
|
||||
+ dev = xhci->ports[port-1].uport->dev;
|
||||
|
||||
- if (port < 1 || port > MAXPORTS) {
|
||||
+ if (port < 1 || port > xhci->numports) {
|
||||
fprintf(stderr, "xhci: bad port %d\n", port);
|
||||
return CC_TRB_ERROR;
|
||||
} else if (!dev) {
|
||||
@@ -1987,7 +2017,7 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr
|
||||
static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
|
||||
{
|
||||
dma_addr_t ctx;
|
||||
- uint8_t bw_ctx[MAXPORTS+1];
|
||||
+ uint8_t bw_ctx[xhci->numports+1];
|
||||
|
||||
DPRINTF("xhci_get_port_bandwidth()\n");
|
||||
|
||||
@@ -1997,7 +2027,7 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
|
||||
|
||||
/* TODO: actually implement real values here */
|
||||
bw_ctx[0] = 0;
|
||||
- memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */
|
||||
+ memset(&bw_ctx[1], 80, xhci->numports); /* 80% */
|
||||
pci_dma_write(&xhci->pci_dev, ctx, bw_ctx, sizeof(bw_ctx));
|
||||
|
||||
return CC_SUCCESS;
|
||||
@@ -2167,12 +2197,11 @@ static void xhci_process_commands(XHCIState *xhci)
|
||||
|
||||
static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
|
||||
{
|
||||
- int nr = port->port.index + 1;
|
||||
-
|
||||
port->portsc = PORTSC_PP;
|
||||
- if (port->port.dev && port->port.dev->attached && !is_detach) {
|
||||
+ if (port->uport->dev && port->uport->dev->attached && !is_detach &&
|
||||
+ (1 << port->uport->dev->speed) & port->speedmask) {
|
||||
port->portsc |= PORTSC_CCS;
|
||||
- switch (port->port.dev->speed) {
|
||||
+ switch (port->uport->dev->speed) {
|
||||
case USB_SPEED_LOW:
|
||||
port->portsc |= PORTSC_SPEED_LOW;
|
||||
break;
|
||||
@@ -2182,14 +2211,18 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
|
||||
case USB_SPEED_HIGH:
|
||||
port->portsc |= PORTSC_SPEED_HIGH;
|
||||
break;
|
||||
+ case USB_SPEED_SUPER:
|
||||
+ port->portsc |= PORTSC_SPEED_SUPER;
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
|
||||
if (xhci_running(xhci)) {
|
||||
port->portsc |= PORTSC_CSC;
|
||||
- XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
|
||||
+ XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
|
||||
+ port->portnr << 24};
|
||||
xhci_event(xhci, &ev);
|
||||
- DPRINTF("xhci: port change event for port %d\n", nr);
|
||||
+ DPRINTF("xhci: port change event for port %d\n", port->portnr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2217,7 +2250,7 @@ static void xhci_reset(DeviceState *dev)
|
||||
xhci_disable_slot(xhci, i+1);
|
||||
}
|
||||
|
||||
- for (i = 0; i < MAXPORTS; i++) {
|
||||
+ for (i = 0; i < xhci->numports; i++) {
|
||||
xhci_update_port(xhci, xhci->ports + i, 0);
|
||||
}
|
||||
|
||||
@@ -2248,7 +2281,8 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
|
||||
ret = 0x01000000 | LEN_CAP;
|
||||
break;
|
||||
case 0x04: /* HCSPARAMS 1 */
|
||||
- ret = (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS;
|
||||
+ ret = ((xhci->numports_2+xhci->numports_3)<<24)
|
||||
+ | (MAXINTRS<<8) | MAXSLOTS;
|
||||
break;
|
||||
case 0x08: /* HCSPARAMS 2 */
|
||||
ret = 0x0000000f;
|
||||
@@ -2278,7 +2312,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
|
||||
ret = 0x20425455; /* "USB " */
|
||||
break;
|
||||
case 0x28: /* Supported Protocol:08 */
|
||||
- ret = 0x00000001 | (USB2_PORTS<<8);
|
||||
+ ret = 0x00000001 | (xhci->numports_2<<8);
|
||||
break;
|
||||
case 0x2c: /* Supported Protocol:0c */
|
||||
ret = 0x00000000; /* reserved */
|
||||
@@ -2290,7 +2324,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
|
||||
ret = 0x20425455; /* "USB " */
|
||||
break;
|
||||
case 0x38: /* Supported Protocol:08 */
|
||||
- ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8);
|
||||
+ ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8);
|
||||
break;
|
||||
case 0x3c: /* Supported Protocol:0c */
|
||||
ret = 0x00000000; /* reserved */
|
||||
@@ -2309,7 +2343,7 @@ static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg)
|
||||
uint32_t port = reg >> 4;
|
||||
uint32_t ret;
|
||||
|
||||
- if (port >= MAXPORTS) {
|
||||
+ if (port >= xhci->numports) {
|
||||
fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
|
||||
ret = 0;
|
||||
goto out;
|
||||
@@ -2342,7 +2376,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
|
||||
trace_usb_xhci_port_write(port, reg & 0x0f, val);
|
||||
|
||||
- if (port >= MAXPORTS) {
|
||||
+ if (port >= xhci->numports) {
|
||||
fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
|
||||
return;
|
||||
}
|
||||
@@ -2364,7 +2398,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
/* write-1-to-start bits */
|
||||
if (val & PORTSC_PR) {
|
||||
DPRINTF("xhci: port %d reset\n", port);
|
||||
- usb_device_reset(xhci->ports[port].port.dev);
|
||||
+ usb_device_reset(xhci->ports[port].uport->dev);
|
||||
portsc |= PORTSC_PRC | PORTSC_PED;
|
||||
}
|
||||
xhci->ports[port].portsc = portsc;
|
||||
@@ -2659,7 +2693,7 @@ static const MemoryRegionOps xhci_mem_ops = {
|
||||
static void xhci_attach(USBPort *usbport)
|
||||
{
|
||||
XHCIState *xhci = usbport->opaque;
|
||||
- XHCIPort *port = &xhci->ports[usbport->index];
|
||||
+ XHCIPort *port = xhci_lookup_port(xhci, usbport);
|
||||
|
||||
xhci_update_port(xhci, port, 0);
|
||||
}
|
||||
@@ -2667,7 +2701,7 @@ static void xhci_attach(USBPort *usbport)
|
||||
static void xhci_detach(USBPort *usbport)
|
||||
{
|
||||
XHCIState *xhci = usbport->opaque;
|
||||
- XHCIPort *port = &xhci->ports[usbport->index];
|
||||
+ XHCIPort *port = xhci_lookup_port(xhci, usbport);
|
||||
|
||||
xhci_update_port(xhci, port, 1);
|
||||
}
|
||||
@@ -2675,9 +2709,9 @@ static void xhci_detach(USBPort *usbport)
|
||||
static void xhci_wakeup(USBPort *usbport)
|
||||
{
|
||||
XHCIState *xhci = usbport->opaque;
|
||||
- XHCIPort *port = &xhci->ports[usbport->index];
|
||||
- int nr = port->port.index + 1;
|
||||
- XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
|
||||
+ XHCIPort *port = xhci_lookup_port(xhci, usbport);
|
||||
+ XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
|
||||
+ port->portnr << 24};
|
||||
uint32_t pls;
|
||||
|
||||
pls = (port->portsc >> PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK;
|
||||
@@ -2759,22 +2793,43 @@ static USBBusOps xhci_bus_ops = {
|
||||
|
||||
static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
|
||||
{
|
||||
- int i;
|
||||
+ XHCIPort *port;
|
||||
+ int i, usbports, speedmask;
|
||||
|
||||
xhci->usbsts = USBSTS_HCH;
|
||||
|
||||
+ if (xhci->numports_2 > MAXPORTS_2) {
|
||||
+ xhci->numports_2 = MAXPORTS_2;
|
||||
+ }
|
||||
+ if (xhci->numports_3 > MAXPORTS_3) {
|
||||
+ xhci->numports_3 = MAXPORTS_3;
|
||||
+ }
|
||||
+ usbports = MAX(xhci->numports_2, xhci->numports_3);
|
||||
+ xhci->numports = xhci->numports_2 + xhci->numports_3;
|
||||
+
|
||||
usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev);
|
||||
|
||||
- for (i = 0; i < MAXPORTS; i++) {
|
||||
- memset(&xhci->ports[i], 0, sizeof(xhci->ports[i]));
|
||||
- usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i,
|
||||
- &xhci_port_ops,
|
||||
- USB_SPEED_MASK_LOW |
|
||||
- USB_SPEED_MASK_FULL |
|
||||
- USB_SPEED_MASK_HIGH);
|
||||
- }
|
||||
- for (i = 0; i < MAXSLOTS; i++) {
|
||||
- xhci->slots[i].enabled = 0;
|
||||
+ for (i = 0; i < usbports; i++) {
|
||||
+ speedmask = 0;
|
||||
+ if (i < xhci->numports_2) {
|
||||
+ port = &xhci->ports[i];
|
||||
+ port->portnr = i + 1;
|
||||
+ port->uport = &xhci->uports[i];
|
||||
+ port->speedmask =
|
||||
+ USB_SPEED_MASK_LOW |
|
||||
+ USB_SPEED_MASK_FULL |
|
||||
+ USB_SPEED_MASK_HIGH;
|
||||
+ speedmask |= port->speedmask;
|
||||
+ }
|
||||
+ if (i < xhci->numports_3) {
|
||||
+ port = &xhci->ports[i + xhci->numports_2];
|
||||
+ port->portnr = i + 1 + xhci->numports_2;
|
||||
+ port->uport = &xhci->uports[i];
|
||||
+ port->speedmask = USB_SPEED_MASK_SUPER;
|
||||
+ speedmask |= port->speedmask;
|
||||
+ }
|
||||
+ usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i,
|
||||
+ &xhci_port_ops, speedmask);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2830,6 +2885,8 @@ static const VMStateDescription vmstate_xhci = {
|
||||
|
||||
static Property xhci_properties[] = {
|
||||
DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
|
||||
+ DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
|
||||
+ DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
64
0341-usb3-superspeed-descriptors.patch
Normal file
64
0341-usb3-superspeed-descriptors.patch
Normal file
@ -0,0 +1,64 @@
|
||||
From f25f31e864756f27f6a94ab7e66b20061291ffa5 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 17:28:50 +0200
|
||||
Subject: [PATCH 341/366] usb3: superspeed descriptors
|
||||
|
||||
Add superspeed descriptor entry to USBDesc,
|
||||
advertise superspeed support when present.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/desc.c | 10 +++++++++-
|
||||
hw/usb/desc.h | 1 +
|
||||
2 files changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
|
||||
index 0a9d3c9..3e8c6cb 100644
|
||||
--- a/hw/usb/desc.c
|
||||
+++ b/hw/usb/desc.c
|
||||
@@ -359,6 +359,9 @@ static void usb_desc_setdefaults(USBDevice *dev)
|
||||
case USB_SPEED_HIGH:
|
||||
dev->device = desc->high;
|
||||
break;
|
||||
+ case USB_SPEED_SUPER:
|
||||
+ dev->device = desc->super;
|
||||
+ break;
|
||||
}
|
||||
usb_desc_set_config(dev, 0);
|
||||
}
|
||||
@@ -376,6 +379,9 @@ void usb_desc_init(USBDevice *dev)
|
||||
if (desc->high) {
|
||||
dev->speedmask |= USB_SPEED_MASK_HIGH;
|
||||
}
|
||||
+ if (desc->super) {
|
||||
+ dev->speedmask |= USB_SPEED_MASK_SUPER;
|
||||
+ }
|
||||
usb_desc_setdefaults(dev);
|
||||
}
|
||||
|
||||
@@ -384,7 +390,9 @@ void usb_desc_attach(USBDevice *dev)
|
||||
const USBDesc *desc = usb_device_get_usb_desc(dev);
|
||||
|
||||
assert(desc != NULL);
|
||||
- if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
|
||||
+ if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) {
|
||||
+ dev->speed = USB_SPEED_SUPER;
|
||||
+ } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
|
||||
dev->speed = USB_SPEED_HIGH;
|
||||
} else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
|
||||
dev->speed = USB_SPEED_FULL;
|
||||
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
|
||||
index 7cf5442..d89fa41 100644
|
||||
--- a/hw/usb/desc.h
|
||||
+++ b/hw/usb/desc.h
|
||||
@@ -152,6 +152,7 @@ struct USBDesc {
|
||||
USBDescID id;
|
||||
const USBDescDevice *full;
|
||||
const USBDescDevice *high;
|
||||
+ const USBDescDevice *super;
|
||||
const char* const *str;
|
||||
};
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
248
0342-usb3-superspeed-endpoint-companion.patch
Normal file
248
0342-usb3-superspeed-endpoint-companion.patch
Normal file
@ -0,0 +1,248 @@
|
||||
From 5a02a74430f4628a78f43242afbb1377deea4c80 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 17:28:03 +0200
|
||||
Subject: [PATCH 342/366] usb3: superspeed endpoint companion
|
||||
|
||||
Add support for building superspeed endpoint companion descriptors,
|
||||
create them for superspeed usb devices.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb.h | 1 +
|
||||
hw/usb/desc.c | 55 ++++++++++++++++++++++++++++++++++++++++---------------
|
||||
hw/usb/desc.h | 26 +++++++++++++++++++++-----
|
||||
3 files changed, 62 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/hw/usb.h b/hw/usb.h
|
||||
index 684e3f4..78ffdf4 100644
|
||||
--- a/hw/usb.h
|
||||
+++ b/hw/usb.h
|
||||
@@ -137,6 +137,7 @@
|
||||
#define USB_DT_INTERFACE_ASSOC 0x0B
|
||||
#define USB_DT_CS_INTERFACE 0x24
|
||||
#define USB_DT_CS_ENDPOINT 0x25
|
||||
+#define USB_DT_ENDPOINT_COMPANION 0x30
|
||||
|
||||
#define USB_ENDPOINT_XFER_CONTROL 0
|
||||
#define USB_ENDPOINT_XFER_ISOC 1
|
||||
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
|
||||
index 3e8c6cb..8f5a8e5 100644
|
||||
--- a/hw/usb/desc.c
|
||||
+++ b/hw/usb/desc.c
|
||||
@@ -76,7 +76,8 @@ int usb_desc_device_qualifier(const USBDescDevice *dev,
|
||||
return bLength;
|
||||
}
|
||||
|
||||
-int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
|
||||
+int usb_desc_config(const USBDescConfig *conf, int flags,
|
||||
+ uint8_t *dest, size_t len)
|
||||
{
|
||||
uint8_t bLength = 0x09;
|
||||
uint16_t wTotalLength = 0;
|
||||
@@ -99,7 +100,7 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
|
||||
|
||||
/* handle grouped interfaces if any */
|
||||
for (i = 0; i < conf->nif_groups; i++) {
|
||||
- rc = usb_desc_iface_group(&(conf->if_groups[i]),
|
||||
+ rc = usb_desc_iface_group(&(conf->if_groups[i]), flags,
|
||||
dest + wTotalLength,
|
||||
len - wTotalLength);
|
||||
if (rc < 0) {
|
||||
@@ -110,7 +111,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
|
||||
|
||||
/* handle normal (ungrouped / no IAD) interfaces if any */
|
||||
for (i = 0; i < conf->nif; i++) {
|
||||
- rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength);
|
||||
+ rc = usb_desc_iface(conf->ifs + i, flags,
|
||||
+ dest + wTotalLength, len - wTotalLength);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
@@ -122,8 +124,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
|
||||
return wTotalLength;
|
||||
}
|
||||
|
||||
-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
|
||||
- size_t len)
|
||||
+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
|
||||
+ uint8_t *dest, size_t len)
|
||||
{
|
||||
int pos = 0;
|
||||
int i = 0;
|
||||
@@ -147,7 +149,7 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
|
||||
|
||||
/* handle associated interfaces in this group */
|
||||
for (i = 0; i < iad->nif; i++) {
|
||||
- int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos);
|
||||
+ int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
@@ -157,7 +159,8 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
|
||||
return pos;
|
||||
}
|
||||
|
||||
-int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
|
||||
+int usb_desc_iface(const USBDescIface *iface, int flags,
|
||||
+ uint8_t *dest, size_t len)
|
||||
{
|
||||
uint8_t bLength = 0x09;
|
||||
int i, rc, pos = 0;
|
||||
@@ -188,7 +191,7 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
|
||||
}
|
||||
|
||||
for (i = 0; i < iface->bNumEndpoints; i++) {
|
||||
- rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos);
|
||||
+ rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
@@ -198,13 +201,15 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
|
||||
return pos;
|
||||
}
|
||||
|
||||
-int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
|
||||
+int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
|
||||
+ uint8_t *dest, size_t len)
|
||||
{
|
||||
uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
|
||||
uint8_t extralen = ep->extra ? ep->extra[0] : 0;
|
||||
+ uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0;
|
||||
USBDescriptor *d = (void *)dest;
|
||||
|
||||
- if (len < bLength + extralen) {
|
||||
+ if (len < bLength + extralen + superlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -224,7 +229,21 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
|
||||
memcpy(dest + bLength, ep->extra, extralen);
|
||||
}
|
||||
|
||||
- return bLength + extralen;
|
||||
+ if (superlen) {
|
||||
+ USBDescriptor *d = (void *)(dest + bLength + extralen);
|
||||
+
|
||||
+ d->bLength = 0x06;
|
||||
+ d->bDescriptorType = USB_DT_ENDPOINT_COMPANION;
|
||||
+
|
||||
+ d->u.super_endpoint.bMaxBurst = ep->bMaxBurst;
|
||||
+ d->u.super_endpoint.bmAttributes = ep->bmAttributes_super;
|
||||
+ d->u.super_endpoint.wBytesPerInterval_lo =
|
||||
+ usb_lo(ep->wBytesPerInterval);
|
||||
+ d->u.super_endpoint.wBytesPerInterval_hi =
|
||||
+ usb_hi(ep->wBytesPerInterval);
|
||||
+ }
|
||||
+
|
||||
+ return bLength + extralen + superlen;
|
||||
}
|
||||
|
||||
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
|
||||
@@ -509,7 +528,7 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
||||
uint8_t buf[256];
|
||||
uint8_t type = value >> 8;
|
||||
uint8_t index = value & 0xff;
|
||||
- int ret = -1;
|
||||
+ int flags, ret = -1;
|
||||
|
||||
if (dev->speed == USB_SPEED_HIGH) {
|
||||
other_dev = usb_device_get_usb_desc(dev)->full;
|
||||
@@ -517,6 +536,11 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
||||
other_dev = usb_device_get_usb_desc(dev)->high;
|
||||
}
|
||||
|
||||
+ flags = 0;
|
||||
+ if (dev->device->bcdUSB >= 0x0300) {
|
||||
+ flags |= USB_DESC_FLAG_SUPER;
|
||||
+ }
|
||||
+
|
||||
switch(type) {
|
||||
case USB_DT_DEVICE:
|
||||
ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
|
||||
@@ -524,7 +548,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
||||
break;
|
||||
case USB_DT_CONFIG:
|
||||
if (index < dev->device->bNumConfigurations) {
|
||||
- ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf));
|
||||
+ ret = usb_desc_config(dev->device->confs + index, flags,
|
||||
+ buf, sizeof(buf));
|
||||
}
|
||||
trace_usb_desc_config(dev->addr, index, len, ret);
|
||||
break;
|
||||
@@ -532,7 +557,6 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
||||
ret = usb_desc_string(dev, index, buf, sizeof(buf));
|
||||
trace_usb_desc_string(dev->addr, index, len, ret);
|
||||
break;
|
||||
-
|
||||
case USB_DT_DEVICE_QUALIFIER:
|
||||
if (other_dev != NULL) {
|
||||
ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
|
||||
@@ -541,7 +565,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
||||
break;
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
if (other_dev != NULL && index < other_dev->bNumConfigurations) {
|
||||
- ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf));
|
||||
+ ret = usb_desc_config(other_dev->confs + index, flags,
|
||||
+ buf, sizeof(buf));
|
||||
buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
|
||||
}
|
||||
trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
|
||||
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
|
||||
index d89fa41..4b5e88d 100644
|
||||
--- a/hw/usb/desc.h
|
||||
+++ b/hw/usb/desc.h
|
||||
@@ -63,6 +63,12 @@ typedef struct USBDescriptor {
|
||||
uint8_t bRefresh; /* only audio ep */
|
||||
uint8_t bSynchAddress; /* only audio ep */
|
||||
} endpoint;
|
||||
+ struct {
|
||||
+ uint8_t bMaxBurst;
|
||||
+ uint8_t bmAttributes;
|
||||
+ uint8_t wBytesPerInterval_lo;
|
||||
+ uint8_t wBytesPerInterval_hi;
|
||||
+ } super_endpoint;
|
||||
} u;
|
||||
} QEMU_PACKED USBDescriptor;
|
||||
|
||||
@@ -139,6 +145,11 @@ struct USBDescEndpoint {
|
||||
|
||||
uint8_t is_audio; /* has bRefresh + bSynchAddress */
|
||||
uint8_t *extra;
|
||||
+
|
||||
+ /* superspeed endpoint companion */
|
||||
+ uint8_t bMaxBurst;
|
||||
+ uint8_t bmAttributes_super;
|
||||
+ uint16_t wBytesPerInterval;
|
||||
};
|
||||
|
||||
struct USBDescOther {
|
||||
@@ -156,16 +167,21 @@ struct USBDesc {
|
||||
const char* const *str;
|
||||
};
|
||||
|
||||
+#define USB_DESC_FLAG_SUPER (1 << 1)
|
||||
+
|
||||
/* generate usb packages from structs */
|
||||
int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
|
||||
uint8_t *dest, size_t len);
|
||||
int usb_desc_device_qualifier(const USBDescDevice *dev,
|
||||
uint8_t *dest, size_t len);
|
||||
-int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len);
|
||||
-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
|
||||
- size_t len);
|
||||
-int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len);
|
||||
-int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
|
||||
+int usb_desc_config(const USBDescConfig *conf, int flags,
|
||||
+ uint8_t *dest, size_t len);
|
||||
+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
|
||||
+ uint8_t *dest, size_t len);
|
||||
+int usb_desc_iface(const USBDescIface *iface, int flags,
|
||||
+ uint8_t *dest, size_t len);
|
||||
+int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
|
||||
+ uint8_t *dest, size_t len);
|
||||
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
|
||||
|
||||
/* control message emulation helpers */
|
||||
--
|
||||
1.7.12
|
||||
|
215
0343-usb3-bos-decriptor.patch
Normal file
215
0343-usb3-bos-decriptor.patch
Normal file
@ -0,0 +1,215 @@
|
||||
From 52666569c1aa34531c101e005feccec0899c14e2 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 17:46:29 +0200
|
||||
Subject: [PATCH 343/366] usb3: bos decriptor
|
||||
|
||||
Add support for creating BOS descriptor and
|
||||
device cappability descriptors.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb.h | 6 ++++
|
||||
hw/usb/desc.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
hw/usb/desc.h | 25 ++++++++++++++
|
||||
trace-events | 1 +
|
||||
4 files changed, 141 insertions(+)
|
||||
|
||||
diff --git a/hw/usb.h b/hw/usb.h
|
||||
index 78ffdf4..48c8926 100644
|
||||
--- a/hw/usb.h
|
||||
+++ b/hw/usb.h
|
||||
@@ -135,10 +135,16 @@
|
||||
#define USB_DT_OTHER_SPEED_CONFIG 0x07
|
||||
#define USB_DT_DEBUG 0x0A
|
||||
#define USB_DT_INTERFACE_ASSOC 0x0B
|
||||
+#define USB_DT_BOS 0x0F
|
||||
+#define USB_DT_DEVICE_CAPABILITY 0x10
|
||||
#define USB_DT_CS_INTERFACE 0x24
|
||||
#define USB_DT_CS_ENDPOINT 0x25
|
||||
#define USB_DT_ENDPOINT_COMPANION 0x30
|
||||
|
||||
+#define USB_DEV_CAP_WIRELESS 0x01
|
||||
+#define USB_DEV_CAP_USB2_EXT 0x02
|
||||
+#define USB_DEV_CAP_SUPERSPEED 0x03
|
||||
+
|
||||
#define USB_ENDPOINT_XFER_CONTROL 0
|
||||
#define USB_ENDPOINT_XFER_ISOC 1
|
||||
#define USB_ENDPOINT_XFER_BULK 2
|
||||
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
|
||||
index 8f5a8e5..1f12eae 100644
|
||||
--- a/hw/usb/desc.c
|
||||
+++ b/hw/usb/desc.c
|
||||
@@ -258,6 +258,111 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
|
||||
return bLength;
|
||||
}
|
||||
|
||||
+static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len)
|
||||
+{
|
||||
+ uint8_t bLength = 0x07;
|
||||
+ USBDescriptor *d = (void *)dest;
|
||||
+
|
||||
+ if (len < bLength) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ d->bLength = bLength;
|
||||
+ d->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
|
||||
+ d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT;
|
||||
+
|
||||
+ d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */
|
||||
+ d->u.cap.u.usb2_ext.bmAttributes_2 = 0;
|
||||
+ d->u.cap.u.usb2_ext.bmAttributes_3 = 0;
|
||||
+ d->u.cap.u.usb2_ext.bmAttributes_4 = 0;
|
||||
+
|
||||
+ return bLength;
|
||||
+}
|
||||
+
|
||||
+static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len)
|
||||
+{
|
||||
+ uint8_t bLength = 0x0a;
|
||||
+ USBDescriptor *d = (void *)dest;
|
||||
+
|
||||
+ if (len < bLength) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ d->bLength = bLength;
|
||||
+ d->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
|
||||
+ d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED;
|
||||
+
|
||||
+ d->u.cap.u.super.bmAttributes = 0;
|
||||
+ d->u.cap.u.super.wSpeedsSupported_lo = 0;
|
||||
+ d->u.cap.u.super.wSpeedsSupported_hi = 0;
|
||||
+ d->u.cap.u.super.bFunctionalitySupport = 0;
|
||||
+ d->u.cap.u.super.bU1DevExitLat = 0x0a;
|
||||
+ d->u.cap.u.super.wU2DevExitLat_lo = 0x20;
|
||||
+ d->u.cap.u.super.wU2DevExitLat_hi = 0;
|
||||
+
|
||||
+ if (desc->full) {
|
||||
+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1);
|
||||
+ d->u.cap.u.super.bFunctionalitySupport = 1;
|
||||
+ }
|
||||
+ if (desc->high) {
|
||||
+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2);
|
||||
+ if (!d->u.cap.u.super.bFunctionalitySupport) {
|
||||
+ d->u.cap.u.super.bFunctionalitySupport = 2;
|
||||
+ }
|
||||
+ }
|
||||
+ if (desc->super) {
|
||||
+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3);
|
||||
+ if (!d->u.cap.u.super.bFunctionalitySupport) {
|
||||
+ d->u.cap.u.super.bFunctionalitySupport = 3;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return bLength;
|
||||
+}
|
||||
+
|
||||
+static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len)
|
||||
+{
|
||||
+ uint8_t bLength = 0x05;
|
||||
+ uint16_t wTotalLength = 0;
|
||||
+ uint8_t bNumDeviceCaps = 0;
|
||||
+ USBDescriptor *d = (void *)dest;
|
||||
+ int rc;
|
||||
+
|
||||
+ if (len < bLength) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ d->bLength = bLength;
|
||||
+ d->bDescriptorType = USB_DT_BOS;
|
||||
+
|
||||
+ wTotalLength += bLength;
|
||||
+
|
||||
+ if (desc->high != NULL) {
|
||||
+ rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength,
|
||||
+ len - wTotalLength);
|
||||
+ if (rc < 0) {
|
||||
+ return rc;
|
||||
+ }
|
||||
+ wTotalLength += rc;
|
||||
+ bNumDeviceCaps++;
|
||||
+ }
|
||||
+
|
||||
+ if (desc->super != NULL) {
|
||||
+ rc = usb_desc_cap_super(desc, dest + wTotalLength,
|
||||
+ len - wTotalLength);
|
||||
+ if (rc < 0) {
|
||||
+ return rc;
|
||||
+ }
|
||||
+ wTotalLength += rc;
|
||||
+ bNumDeviceCaps++;
|
||||
+ }
|
||||
+
|
||||
+ d->u.bos.wTotalLength_lo = usb_lo(wTotalLength);
|
||||
+ d->u.bos.wTotalLength_hi = usb_hi(wTotalLength);
|
||||
+ d->u.bos.bNumDeviceCaps = bNumDeviceCaps;
|
||||
+ return wTotalLength;
|
||||
+}
|
||||
+
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void usb_desc_ep_init(USBDevice *dev)
|
||||
@@ -571,6 +676,10 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
||||
}
|
||||
trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
|
||||
break;
|
||||
+ case USB_DT_BOS:
|
||||
+ ret = usb_desc_bos(desc, buf, sizeof(buf));
|
||||
+ trace_usb_desc_bos(dev->addr, len, ret);
|
||||
+ break;
|
||||
|
||||
case USB_DT_DEBUG:
|
||||
/* ignore silently */
|
||||
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
|
||||
index 4b5e88d..68bb570 100644
|
||||
--- a/hw/usb/desc.h
|
||||
+++ b/hw/usb/desc.h
|
||||
@@ -69,6 +69,31 @@ typedef struct USBDescriptor {
|
||||
uint8_t wBytesPerInterval_lo;
|
||||
uint8_t wBytesPerInterval_hi;
|
||||
} super_endpoint;
|
||||
+ struct {
|
||||
+ uint8_t wTotalLength_lo;
|
||||
+ uint8_t wTotalLength_hi;
|
||||
+ uint8_t bNumDeviceCaps;
|
||||
+ } bos;
|
||||
+ struct {
|
||||
+ uint8_t bDevCapabilityType;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ uint8_t bmAttributes_1;
|
||||
+ uint8_t bmAttributes_2;
|
||||
+ uint8_t bmAttributes_3;
|
||||
+ uint8_t bmAttributes_4;
|
||||
+ } usb2_ext;
|
||||
+ struct {
|
||||
+ uint8_t bmAttributes;
|
||||
+ uint8_t wSpeedsSupported_lo;
|
||||
+ uint8_t wSpeedsSupported_hi;
|
||||
+ uint8_t bFunctionalitySupport;
|
||||
+ uint8_t bU1DevExitLat;
|
||||
+ uint8_t wU2DevExitLat_lo;
|
||||
+ uint8_t wU2DevExitLat_hi;
|
||||
+ } super;
|
||||
+ } u;
|
||||
+ } cap;
|
||||
} u;
|
||||
} QEMU_PACKED USBDescriptor;
|
||||
|
||||
diff --git a/trace-events b/trace-events
|
||||
index a894689..5bc591a 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -340,6 +340,7 @@ usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device quali
|
||||
usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
|
||||
usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
|
||||
usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
|
||||
+usb_desc_bos(int addr, int len, int ret) "dev %d bos, len %d, ret %d"
|
||||
usb_set_addr(int addr) "dev %d"
|
||||
usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
|
||||
usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d"
|
||||
--
|
||||
1.7.12
|
||||
|
94
0344-usb-storage-usb3-support.patch
Normal file
94
0344-usb-storage-usb3-support.patch
Normal file
@ -0,0 +1,94 @@
|
||||
From 4a6f1fdf12d8b03633dad54dadc12781a77fbf6b Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 28 Aug 2012 17:29:15 +0200
|
||||
Subject: [PATCH 344/366] usb-storage: usb3 support
|
||||
|
||||
Add usb3 descriptors to usb-storage, so it shows up as superspeed
|
||||
device when connected to xhci.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/dev-storage.c | 46 +++++++++++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 43 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
|
||||
index ff48d91..e732191 100644
|
||||
--- a/hw/usb/dev-storage.c
|
||||
+++ b/hw/usb/dev-storage.c
|
||||
@@ -78,6 +78,7 @@ enum {
|
||||
STR_SERIALNUMBER,
|
||||
STR_CONFIG_FULL,
|
||||
STR_CONFIG_HIGH,
|
||||
+ STR_CONFIG_SUPER,
|
||||
};
|
||||
|
||||
static const USBDescStrings desc_strings = {
|
||||
@@ -86,6 +87,7 @@ static const USBDescStrings desc_strings = {
|
||||
[STR_SERIALNUMBER] = "1",
|
||||
[STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
|
||||
[STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
|
||||
+ [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
|
||||
};
|
||||
|
||||
static const USBDescIface desc_iface_full = {
|
||||
@@ -158,6 +160,43 @@ static const USBDescDevice desc_device_high = {
|
||||
},
|
||||
};
|
||||
|
||||
+static const USBDescIface desc_iface_super = {
|
||||
+ .bInterfaceNumber = 0,
|
||||
+ .bNumEndpoints = 2,
|
||||
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
|
||||
+ .bInterfaceSubClass = 0x06, /* SCSI */
|
||||
+ .bInterfaceProtocol = 0x50, /* Bulk */
|
||||
+ .eps = (USBDescEndpoint[]) {
|
||||
+ {
|
||||
+ .bEndpointAddress = USB_DIR_IN | 0x01,
|
||||
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
+ .wMaxPacketSize = 1024,
|
||||
+ .bMaxBurst = 15,
|
||||
+ },{
|
||||
+ .bEndpointAddress = USB_DIR_OUT | 0x02,
|
||||
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
+ .wMaxPacketSize = 1024,
|
||||
+ .bMaxBurst = 15,
|
||||
+ },
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static const USBDescDevice desc_device_super = {
|
||||
+ .bcdUSB = 0x0300,
|
||||
+ .bMaxPacketSize0 = 9,
|
||||
+ .bNumConfigurations = 1,
|
||||
+ .confs = (USBDescConfig[]) {
|
||||
+ {
|
||||
+ .bNumInterfaces = 1,
|
||||
+ .bConfigurationValue = 1,
|
||||
+ .iConfiguration = STR_CONFIG_SUPER,
|
||||
+ .bmAttributes = 0xc0,
|
||||
+ .nif = 1,
|
||||
+ .ifs = &desc_iface_super,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static const USBDesc desc = {
|
||||
.id = {
|
||||
.idVendor = 0x46f4, /* CRC16() of "QEMU" */
|
||||
@@ -167,9 +206,10 @@ static const USBDesc desc = {
|
||||
.iProduct = STR_PRODUCT,
|
||||
.iSerialNumber = STR_SERIALNUMBER,
|
||||
},
|
||||
- .full = &desc_device_full,
|
||||
- .high = &desc_device_high,
|
||||
- .str = desc_strings,
|
||||
+ .full = &desc_device_full,
|
||||
+ .high = &desc_device_high,
|
||||
+ .super = &desc_device_super,
|
||||
+ .str = desc_strings,
|
||||
};
|
||||
|
||||
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
|
||||
--
|
||||
1.7.12
|
||||
|
96
0345-xhci-fix-cleanup-msi.patch
Normal file
96
0345-xhci-fix-cleanup-msi.patch
Normal file
@ -0,0 +1,96 @@
|
||||
From 3ed11ea2c3b6d5db29246b4da105902aa0346d65 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 10:57:12 +0200
|
||||
Subject: [PATCH 345/366] xhci: fix & cleanup msi.
|
||||
|
||||
Drop custom write_config function which isn't needed any more.
|
||||
Make the msi property a bit property so it accepts 'on' & 'off'.
|
||||
Enable MSI by default.
|
||||
|
||||
TODO: add compat property to disable on old machine types.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 27 +++++++++------------------
|
||||
1 file changed, 9 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index e08312e..e1d5d2a 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -386,7 +386,7 @@ struct XHCIState {
|
||||
/* properties */
|
||||
uint32_t numports_2;
|
||||
uint32_t numports_3;
|
||||
- uint32_t msi;
|
||||
+ uint32_t flags;
|
||||
|
||||
/* Operational Registers */
|
||||
uint32_t usbcmd;
|
||||
@@ -435,6 +435,10 @@ typedef struct XHCIEvRingSeg {
|
||||
uint32_t rsvd;
|
||||
} XHCIEvRingSeg;
|
||||
|
||||
+enum xhci_flags {
|
||||
+ XHCI_FLAG_USE_MSI = 1,
|
||||
+};
|
||||
+
|
||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||
unsigned int epid);
|
||||
static void xhci_event(XHCIState *xhci, XHCIEvent *event);
|
||||
@@ -617,7 +621,7 @@ static void xhci_irq_update(XHCIState *xhci)
|
||||
level = 1;
|
||||
}
|
||||
|
||||
- if (xhci->msi && msi_enabled(&xhci->pci_dev)) {
|
||||
+ if (msi_enabled(&xhci->pci_dev)) {
|
||||
if (level) {
|
||||
trace_usb_xhci_irq_msi(0);
|
||||
msi_notify(&xhci->pci_dev, 0);
|
||||
@@ -2859,32 +2863,20 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
|
||||
ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0);
|
||||
assert(ret >= 0);
|
||||
|
||||
- if (xhci->msi) {
|
||||
- ret = msi_init(&xhci->pci_dev, 0x70, 1, true, false);
|
||||
- assert(ret >= 0);
|
||||
+ if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
|
||||
+ msi_init(&xhci->pci_dev, 0x70, MAXINTRS, true, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void xhci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
|
||||
- int len)
|
||||
-{
|
||||
- XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
|
||||
-
|
||||
- pci_default_write_config(dev, addr, val, len);
|
||||
- if (xhci->msi) {
|
||||
- msi_write_config(dev, addr, val, len);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static const VMStateDescription vmstate_xhci = {
|
||||
.name = "xhci",
|
||||
.unmigratable = 1,
|
||||
};
|
||||
|
||||
static Property xhci_properties[] = {
|
||||
- DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
|
||||
+ DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
|
||||
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
|
||||
DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -2904,7 +2896,6 @@ static void xhci_class_init(ObjectClass *klass, void *data)
|
||||
k->class_id = PCI_CLASS_SERIAL_USB;
|
||||
k->revision = 0x03;
|
||||
k->is_express = 1;
|
||||
- k->config_write = xhci_write_config;
|
||||
}
|
||||
|
||||
static TypeInfo xhci_info = {
|
||||
--
|
||||
1.7.12
|
||||
|
117
0346-xhci-rework-interrupt-handling.patch
Normal file
117
0346-xhci-rework-interrupt-handling.patch
Normal file
@ -0,0 +1,117 @@
|
||||
From da881a3422ae525f1d0a24f61117a47473261037 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 13:05:10 +0200
|
||||
Subject: [PATCH 346/366] xhci: rework interrupt handling
|
||||
|
||||
Split xhci_irq_update into a function which handles intx updates
|
||||
(including lowering the irq line once the guests acks the interrupt)
|
||||
and one which is used for raising an irq only.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 47 +++++++++++++++++++++++++++++++++--------------
|
||||
1 file changed, 33 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index e1d5d2a..5eae32e 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -612,24 +612,43 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
|
||||
return &xhci->ports[index];
|
||||
}
|
||||
|
||||
-static void xhci_irq_update(XHCIState *xhci)
|
||||
+static void xhci_intx_update(XHCIState *xhci)
|
||||
{
|
||||
int level = 0;
|
||||
|
||||
- if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE &&
|
||||
+ if (msi_enabled(&xhci->pci_dev)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (xhci->iman & IMAN_IP &&
|
||||
+ xhci->iman & IMAN_IE &&
|
||||
xhci->usbcmd & USBCMD_INTE) {
|
||||
level = 1;
|
||||
}
|
||||
|
||||
+ trace_usb_xhci_irq_intx(level);
|
||||
+ qemu_set_irq(xhci->irq, level);
|
||||
+}
|
||||
+
|
||||
+static void xhci_intr_raise(XHCIState *xhci)
|
||||
+{
|
||||
+ if (!(xhci->iman & IMAN_IP) ||
|
||||
+ !(xhci->iman & IMAN_IE)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!(xhci->usbcmd & USBCMD_INTE)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (msi_enabled(&xhci->pci_dev)) {
|
||||
- if (level) {
|
||||
- trace_usb_xhci_irq_msi(0);
|
||||
- msi_notify(&xhci->pci_dev, 0);
|
||||
- }
|
||||
- } else {
|
||||
- trace_usb_xhci_irq_intx(level);
|
||||
- qemu_set_irq(xhci->irq, level);
|
||||
+ trace_usb_xhci_irq_msi(0);
|
||||
+ msi_notify(&xhci->pci_dev, 0);
|
||||
+ return;
|
||||
}
|
||||
+
|
||||
+ trace_usb_xhci_irq_intx(1);
|
||||
+ qemu_set_irq(xhci->irq, 1);
|
||||
}
|
||||
|
||||
static inline int xhci_running(XHCIState *xhci)
|
||||
@@ -732,7 +751,7 @@ static void xhci_events_update(XHCIState *xhci)
|
||||
xhci->erdp_low |= ERDP_EHB;
|
||||
xhci->iman |= IMAN_IP;
|
||||
xhci->usbsts |= USBSTS_EINT;
|
||||
- xhci_irq_update(xhci);
|
||||
+ xhci_intr_raise(xhci);
|
||||
}
|
||||
|
||||
if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) {
|
||||
@@ -796,7 +815,7 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event)
|
||||
xhci->iman |= IMAN_IP;
|
||||
xhci->usbsts |= USBSTS_EINT;
|
||||
|
||||
- xhci_irq_update(xhci);
|
||||
+ xhci_intr_raise(xhci);
|
||||
}
|
||||
|
||||
static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
|
||||
@@ -2481,13 +2500,13 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
if (val & USBCMD_HCRST) {
|
||||
xhci_reset(&xhci->pci_dev.qdev);
|
||||
}
|
||||
- xhci_irq_update(xhci);
|
||||
+ xhci_intx_update(xhci);
|
||||
break;
|
||||
|
||||
case 0x04: /* USBSTS */
|
||||
/* these bits are write-1-to-clear */
|
||||
xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE));
|
||||
- xhci_irq_update(xhci);
|
||||
+ xhci_intx_update(xhci);
|
||||
break;
|
||||
|
||||
case 0x14: /* DNCTRL */
|
||||
@@ -2572,7 +2591,7 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
}
|
||||
xhci->iman &= ~IMAN_IE;
|
||||
xhci->iman |= val & IMAN_IE;
|
||||
- xhci_irq_update(xhci);
|
||||
+ xhci_intx_update(xhci);
|
||||
break;
|
||||
case 0x24: /* IMOD */
|
||||
xhci->imod = val;
|
||||
--
|
||||
1.7.12
|
||||
|
156
0347-xhci-add-msix-support.patch
Normal file
156
0347-xhci-add-msix-support.patch
Normal file
@ -0,0 +1,156 @@
|
||||
From 03ab86ecf677d777864a3643ec8479037d3f41cd Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 12:06:59 +0200
|
||||
Subject: [PATCH 347/366] xhci: add msix support
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
trace-events | 3 +++
|
||||
2 files changed, 49 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 5eae32e..3bac99a 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "hw/usb.h"
|
||||
#include "hw/pci.h"
|
||||
#include "hw/msi.h"
|
||||
+#include "hw/msix.h"
|
||||
#include "trace.h"
|
||||
|
||||
//#define DEBUG_XHCI
|
||||
@@ -59,6 +60,8 @@
|
||||
#define OFF_OPER LEN_CAP
|
||||
#define OFF_RUNTIME 0x1000
|
||||
#define OFF_DOORBELL 0x2000
|
||||
+#define OFF_MSIX_TABLE 0x3000
|
||||
+#define OFF_MSIX_PBA 0x3800
|
||||
/* must be power of 2 */
|
||||
#define LEN_REGS 0x4000
|
||||
|
||||
@@ -411,6 +414,7 @@ struct XHCIState {
|
||||
uint32_t erstba_high;
|
||||
uint32_t erdp_low;
|
||||
uint32_t erdp_high;
|
||||
+ bool msix_used;
|
||||
|
||||
int64_t mfindex_start;
|
||||
QEMUTimer *mfwrap_timer;
|
||||
@@ -437,6 +441,7 @@ typedef struct XHCIEvRingSeg {
|
||||
|
||||
enum xhci_flags {
|
||||
XHCI_FLAG_USE_MSI = 1,
|
||||
+ XHCI_FLAG_USE_MSI_X,
|
||||
};
|
||||
|
||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||
@@ -616,7 +621,8 @@ static void xhci_intx_update(XHCIState *xhci)
|
||||
{
|
||||
int level = 0;
|
||||
|
||||
- if (msi_enabled(&xhci->pci_dev)) {
|
||||
+ if (msix_enabled(&xhci->pci_dev) ||
|
||||
+ msi_enabled(&xhci->pci_dev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -630,6 +636,30 @@ static void xhci_intx_update(XHCIState *xhci)
|
||||
qemu_set_irq(xhci->irq, level);
|
||||
}
|
||||
|
||||
+static void xhci_msix_update(XHCIState *xhci)
|
||||
+{
|
||||
+ bool enabled;
|
||||
+
|
||||
+ if (!msix_enabled(&xhci->pci_dev)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ enabled = xhci->iman & IMAN_IE;
|
||||
+ if (enabled == xhci->msix_used) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (enabled) {
|
||||
+ trace_usb_xhci_irq_msix_use(0);
|
||||
+ msix_vector_use(&xhci->pci_dev, 0);
|
||||
+ xhci->msix_used = true;
|
||||
+ } else {
|
||||
+ trace_usb_xhci_irq_msix_unuse(0);
|
||||
+ msix_vector_unuse(&xhci->pci_dev, 0);
|
||||
+ xhci->msix_used = false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void xhci_intr_raise(XHCIState *xhci)
|
||||
{
|
||||
if (!(xhci->iman & IMAN_IP) ||
|
||||
@@ -641,6 +671,12 @@ static void xhci_intr_raise(XHCIState *xhci)
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (msix_enabled(&xhci->pci_dev)) {
|
||||
+ trace_usb_xhci_irq_msix(0);
|
||||
+ msix_notify(&xhci->pci_dev, 0);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (msi_enabled(&xhci->pci_dev)) {
|
||||
trace_usb_xhci_irq_msi(0);
|
||||
msi_notify(&xhci->pci_dev, 0);
|
||||
@@ -2284,6 +2320,7 @@ static void xhci_reset(DeviceState *dev)
|
||||
xhci->erstba_high = 0;
|
||||
xhci->erdp_low = 0;
|
||||
xhci->erdp_high = 0;
|
||||
+ xhci->msix_used = 0;
|
||||
|
||||
xhci->er_ep_idx = 0;
|
||||
xhci->er_pcs = 1;
|
||||
@@ -2592,6 +2629,7 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
xhci->iman &= ~IMAN_IE;
|
||||
xhci->iman |= val & IMAN_IE;
|
||||
xhci_intx_update(xhci);
|
||||
+ xhci_msix_update(xhci);
|
||||
break;
|
||||
case 0x24: /* IMOD */
|
||||
xhci->imod = val;
|
||||
@@ -2885,6 +2923,12 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
|
||||
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
|
||||
msi_init(&xhci->pci_dev, 0x70, MAXINTRS, true, false);
|
||||
}
|
||||
+ if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) {
|
||||
+ msix_init(&xhci->pci_dev, MAXINTRS,
|
||||
+ &xhci->mem, 0, OFF_MSIX_TABLE,
|
||||
+ &xhci->mem, 0, OFF_MSIX_PBA,
|
||||
+ 0x90);
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2896,6 +2940,7 @@ static const VMStateDescription vmstate_xhci = {
|
||||
|
||||
static Property xhci_properties[] = {
|
||||
DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
|
||||
+ DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
|
||||
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
|
||||
DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
diff --git a/trace-events b/trace-events
|
||||
index 5bc591a..8589ca4 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -313,6 +313,9 @@ usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x"
|
||||
usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x"
|
||||
usb_xhci_irq_intx(uint32_t level) "level %d"
|
||||
usb_xhci_irq_msi(uint32_t nr) "nr %d"
|
||||
+usb_xhci_irq_msix(uint32_t nr) "nr %d"
|
||||
+usb_xhci_irq_msix_use(uint32_t nr) "nr %d"
|
||||
+usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d"
|
||||
usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
|
||||
--
|
||||
1.7.12
|
||||
|
55
0348-xhci-move-register-update-into-xhci_intr_raise.patch
Normal file
55
0348-xhci-move-register-update-into-xhci_intr_raise.patch
Normal file
@ -0,0 +1,55 @@
|
||||
From c7ca31b2f54b945ba4babf8ad329c938462c75f5 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 14:04:04 +0200
|
||||
Subject: [PATCH 348/366] xhci: move register update into xhci_intr_raise
|
||||
|
||||
Now that we have a separate function to raise an IRQ we can move
|
||||
some comon code into the function.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 14 +++++---------
|
||||
1 file changed, 5 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 3bac99a..e39fe04 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -662,8 +662,11 @@ static void xhci_msix_update(XHCIState *xhci)
|
||||
|
||||
static void xhci_intr_raise(XHCIState *xhci)
|
||||
{
|
||||
- if (!(xhci->iman & IMAN_IP) ||
|
||||
- !(xhci->iman & IMAN_IE)) {
|
||||
+ xhci->erdp_low |= ERDP_EHB;
|
||||
+ xhci->iman |= IMAN_IP;
|
||||
+ xhci->usbsts |= USBSTS_EINT;
|
||||
+
|
||||
+ if (!(xhci->iman & IMAN_IE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -784,9 +787,6 @@ static void xhci_events_update(XHCIState *xhci)
|
||||
}
|
||||
|
||||
if (do_irq) {
|
||||
- xhci->erdp_low |= ERDP_EHB;
|
||||
- xhci->iman |= IMAN_IP;
|
||||
- xhci->usbsts |= USBSTS_EINT;
|
||||
xhci_intr_raise(xhci);
|
||||
}
|
||||
|
||||
@@ -847,10 +847,6 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event)
|
||||
xhci_write_event(xhci, event);
|
||||
}
|
||||
|
||||
- xhci->erdp_low |= ERDP_EHB;
|
||||
- xhci->iman |= IMAN_IP;
|
||||
- xhci->usbsts |= USBSTS_EINT;
|
||||
-
|
||||
xhci_intr_raise(xhci);
|
||||
}
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
642
0349-xhci-add-XHCIInterrupter.patch
Normal file
642
0349-xhci-add-XHCIInterrupter.patch
Normal file
@ -0,0 +1,642 @@
|
||||
From 84ce3d5155c984ad131ba7153b9c3646c88b8636 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 15:49:03 +0200
|
||||
Subject: [PATCH 349/366] xhci: add XHCIInterrupter
|
||||
|
||||
Move all state belonging to the (single) interrupter into a separate
|
||||
struct. First step in adding support for multiple interrupters.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 307 ++++++++++++++++++++++++++++--------------------------
|
||||
trace-events | 2 +-
|
||||
2 files changed, 161 insertions(+), 148 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index e39fe04..ddc3825 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -378,6 +378,27 @@ typedef struct XHCIEvent {
|
||||
uint8_t epid;
|
||||
} XHCIEvent;
|
||||
|
||||
+typedef struct XHCIInterrupter {
|
||||
+ uint32_t iman;
|
||||
+ uint32_t imod;
|
||||
+ uint32_t erstsz;
|
||||
+ uint32_t erstba_low;
|
||||
+ uint32_t erstba_high;
|
||||
+ uint32_t erdp_low;
|
||||
+ uint32_t erdp_high;
|
||||
+
|
||||
+ bool msix_used, er_pcs, er_full;
|
||||
+
|
||||
+ dma_addr_t er_start;
|
||||
+ uint32_t er_size;
|
||||
+ unsigned int er_ep_idx;
|
||||
+
|
||||
+ XHCIEvent ev_buffer[EV_QUEUE];
|
||||
+ unsigned int ev_buffer_put;
|
||||
+ unsigned int ev_buffer_get;
|
||||
+
|
||||
+} XHCIInterrupter;
|
||||
+
|
||||
struct XHCIState {
|
||||
PCIDevice pci_dev;
|
||||
USBBus bus;
|
||||
@@ -407,27 +428,9 @@ struct XHCIState {
|
||||
uint32_t numports;
|
||||
|
||||
/* Runtime Registers */
|
||||
- uint32_t iman;
|
||||
- uint32_t imod;
|
||||
- uint32_t erstsz;
|
||||
- uint32_t erstba_low;
|
||||
- uint32_t erstba_high;
|
||||
- uint32_t erdp_low;
|
||||
- uint32_t erdp_high;
|
||||
- bool msix_used;
|
||||
-
|
||||
int64_t mfindex_start;
|
||||
QEMUTimer *mfwrap_timer;
|
||||
-
|
||||
- dma_addr_t er_start;
|
||||
- uint32_t er_size;
|
||||
- bool er_pcs;
|
||||
- unsigned int er_ep_idx;
|
||||
- bool er_full;
|
||||
-
|
||||
- XHCIEvent ev_buffer[EV_QUEUE];
|
||||
- unsigned int ev_buffer_put;
|
||||
- unsigned int ev_buffer_get;
|
||||
+ XHCIInterrupter intr[MAXINTRS];
|
||||
|
||||
XHCIRing cmd_ring;
|
||||
};
|
||||
@@ -446,8 +449,8 @@ enum xhci_flags {
|
||||
|
||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||
unsigned int epid);
|
||||
-static void xhci_event(XHCIState *xhci, XHCIEvent *event);
|
||||
-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event);
|
||||
+static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
|
||||
+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v);
|
||||
|
||||
static const char *TRBType_names[] = {
|
||||
[TRB_RESERVED] = "TRB_RESERVED",
|
||||
@@ -573,7 +576,7 @@ static void xhci_mfwrap_timer(void *opaque)
|
||||
XHCIState *xhci = opaque;
|
||||
XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS };
|
||||
|
||||
- xhci_event(xhci, &wrap);
|
||||
+ xhci_event(xhci, &wrap, 0);
|
||||
xhci_mfwrap_update(xhci);
|
||||
}
|
||||
|
||||
@@ -626,8 +629,8 @@ static void xhci_intx_update(XHCIState *xhci)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (xhci->iman & IMAN_IP &&
|
||||
- xhci->iman & IMAN_IE &&
|
||||
+ if (xhci->intr[0].iman & IMAN_IP &&
|
||||
+ xhci->intr[0].iman & IMAN_IE &&
|
||||
xhci->usbcmd & USBCMD_INTE) {
|
||||
level = 1;
|
||||
}
|
||||
@@ -636,7 +639,7 @@ static void xhci_intx_update(XHCIState *xhci)
|
||||
qemu_set_irq(xhci->irq, level);
|
||||
}
|
||||
|
||||
-static void xhci_msix_update(XHCIState *xhci)
|
||||
+static void xhci_msix_update(XHCIState *xhci, int v)
|
||||
{
|
||||
bool enabled;
|
||||
|
||||
@@ -644,29 +647,29 @@ static void xhci_msix_update(XHCIState *xhci)
|
||||
return;
|
||||
}
|
||||
|
||||
- enabled = xhci->iman & IMAN_IE;
|
||||
- if (enabled == xhci->msix_used) {
|
||||
+ enabled = xhci->intr[v].iman & IMAN_IE;
|
||||
+ if (enabled == xhci->intr[v].msix_used) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
- trace_usb_xhci_irq_msix_use(0);
|
||||
- msix_vector_use(&xhci->pci_dev, 0);
|
||||
- xhci->msix_used = true;
|
||||
+ trace_usb_xhci_irq_msix_use(v);
|
||||
+ msix_vector_use(&xhci->pci_dev, v);
|
||||
+ xhci->intr[v].msix_used = true;
|
||||
} else {
|
||||
- trace_usb_xhci_irq_msix_unuse(0);
|
||||
- msix_vector_unuse(&xhci->pci_dev, 0);
|
||||
- xhci->msix_used = false;
|
||||
+ trace_usb_xhci_irq_msix_unuse(v);
|
||||
+ msix_vector_unuse(&xhci->pci_dev, v);
|
||||
+ xhci->intr[v].msix_used = false;
|
||||
}
|
||||
}
|
||||
|
||||
-static void xhci_intr_raise(XHCIState *xhci)
|
||||
+static void xhci_intr_raise(XHCIState *xhci, int v)
|
||||
{
|
||||
- xhci->erdp_low |= ERDP_EHB;
|
||||
- xhci->iman |= IMAN_IP;
|
||||
+ xhci->intr[v].erdp_low |= ERDP_EHB;
|
||||
+ xhci->intr[v].iman |= IMAN_IP;
|
||||
xhci->usbsts |= USBSTS_EINT;
|
||||
|
||||
- if (!(xhci->iman & IMAN_IE)) {
|
||||
+ if (!(xhci->intr[v].iman & IMAN_IE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -675,24 +678,26 @@ static void xhci_intr_raise(XHCIState *xhci)
|
||||
}
|
||||
|
||||
if (msix_enabled(&xhci->pci_dev)) {
|
||||
- trace_usb_xhci_irq_msix(0);
|
||||
- msix_notify(&xhci->pci_dev, 0);
|
||||
+ trace_usb_xhci_irq_msix(v);
|
||||
+ msix_notify(&xhci->pci_dev, v);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msi_enabled(&xhci->pci_dev)) {
|
||||
- trace_usb_xhci_irq_msi(0);
|
||||
- msi_notify(&xhci->pci_dev, 0);
|
||||
+ trace_usb_xhci_irq_msi(v);
|
||||
+ msi_notify(&xhci->pci_dev, v);
|
||||
return;
|
||||
}
|
||||
|
||||
- trace_usb_xhci_irq_intx(1);
|
||||
- qemu_set_irq(xhci->irq, 1);
|
||||
+ if (v == 0) {
|
||||
+ trace_usb_xhci_irq_intx(1);
|
||||
+ qemu_set_irq(xhci->irq, 1);
|
||||
+ }
|
||||
}
|
||||
|
||||
static inline int xhci_running(XHCIState *xhci)
|
||||
{
|
||||
- return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full;
|
||||
+ return !(xhci->usbsts & USBSTS_HCH) && !xhci->intr[0].er_full;
|
||||
}
|
||||
|
||||
static void xhci_die(XHCIState *xhci)
|
||||
@@ -701,8 +706,9 @@ static void xhci_die(XHCIState *xhci)
|
||||
fprintf(stderr, "xhci: asserted controller error\n");
|
||||
}
|
||||
|
||||
-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
|
||||
+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
|
||||
{
|
||||
+ XHCIInterrupter *intr = &xhci->intr[v];
|
||||
XHCITRB ev_trb;
|
||||
dma_addr_t addr;
|
||||
|
||||
@@ -710,27 +716,28 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
|
||||
ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24));
|
||||
ev_trb.control = (event->slotid << 24) | (event->epid << 16) |
|
||||
event->flags | (event->type << TRB_TYPE_SHIFT);
|
||||
- if (xhci->er_pcs) {
|
||||
+ if (intr->er_pcs) {
|
||||
ev_trb.control |= TRB_C;
|
||||
}
|
||||
ev_trb.control = cpu_to_le32(ev_trb.control);
|
||||
|
||||
- trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb),
|
||||
+ trace_usb_xhci_queue_event(v, intr->er_ep_idx, trb_name(&ev_trb),
|
||||
event_name(event), ev_trb.parameter,
|
||||
ev_trb.status, ev_trb.control);
|
||||
|
||||
- addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
|
||||
+ addr = intr->er_start + TRB_SIZE*intr->er_ep_idx;
|
||||
pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE);
|
||||
|
||||
- xhci->er_ep_idx++;
|
||||
- if (xhci->er_ep_idx >= xhci->er_size) {
|
||||
- xhci->er_ep_idx = 0;
|
||||
- xhci->er_pcs = !xhci->er_pcs;
|
||||
+ intr->er_ep_idx++;
|
||||
+ if (intr->er_ep_idx >= intr->er_size) {
|
||||
+ intr->er_ep_idx = 0;
|
||||
+ intr->er_pcs = !intr->er_pcs;
|
||||
}
|
||||
}
|
||||
|
||||
-static void xhci_events_update(XHCIState *xhci)
|
||||
+static void xhci_events_update(XHCIState *xhci, int v)
|
||||
{
|
||||
+ XHCIInterrupter *intr = &xhci->intr[v];
|
||||
dma_addr_t erdp;
|
||||
unsigned int dp_idx;
|
||||
bool do_irq = 0;
|
||||
@@ -739,115 +746,116 @@ static void xhci_events_update(XHCIState *xhci)
|
||||
return;
|
||||
}
|
||||
|
||||
- erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
|
||||
- if (erdp < xhci->er_start ||
|
||||
- erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
|
||||
+ erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
|
||||
+ if (erdp < intr->er_start ||
|
||||
+ erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
|
||||
fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
|
||||
- fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n",
|
||||
- xhci->er_start, xhci->er_size);
|
||||
+ fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
|
||||
+ v, intr->er_start, intr->er_size);
|
||||
xhci_die(xhci);
|
||||
return;
|
||||
}
|
||||
- dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
|
||||
- assert(dp_idx < xhci->er_size);
|
||||
+ dp_idx = (erdp - intr->er_start) / TRB_SIZE;
|
||||
+ assert(dp_idx < intr->er_size);
|
||||
|
||||
/* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus
|
||||
* deadlocks when the ER is full. Hack it by holding off events until
|
||||
* the driver decides to free at least half of the ring */
|
||||
- if (xhci->er_full) {
|
||||
- int er_free = dp_idx - xhci->er_ep_idx;
|
||||
+ if (intr->er_full) {
|
||||
+ int er_free = dp_idx - intr->er_ep_idx;
|
||||
if (er_free <= 0) {
|
||||
- er_free += xhci->er_size;
|
||||
+ er_free += intr->er_size;
|
||||
}
|
||||
- if (er_free < (xhci->er_size/2)) {
|
||||
+ if (er_free < (intr->er_size/2)) {
|
||||
DPRINTF("xhci_events_update(): event ring still "
|
||||
"more than half full (hack)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- while (xhci->ev_buffer_put != xhci->ev_buffer_get) {
|
||||
- assert(xhci->er_full);
|
||||
- if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) {
|
||||
+ while (intr->ev_buffer_put != intr->ev_buffer_get) {
|
||||
+ assert(intr->er_full);
|
||||
+ if (((intr->er_ep_idx+1) % intr->er_size) == dp_idx) {
|
||||
DPRINTF("xhci_events_update(): event ring full again\n");
|
||||
#ifndef ER_FULL_HACK
|
||||
XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
|
||||
- xhci_write_event(xhci, &full);
|
||||
+ xhci_write_event(xhci, &full, v);
|
||||
#endif
|
||||
do_irq = 1;
|
||||
break;
|
||||
}
|
||||
- XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get];
|
||||
- xhci_write_event(xhci, event);
|
||||
- xhci->ev_buffer_get++;
|
||||
+ XHCIEvent *event = &intr->ev_buffer[intr->ev_buffer_get];
|
||||
+ xhci_write_event(xhci, event, v);
|
||||
+ intr->ev_buffer_get++;
|
||||
do_irq = 1;
|
||||
- if (xhci->ev_buffer_get == EV_QUEUE) {
|
||||
- xhci->ev_buffer_get = 0;
|
||||
+ if (intr->ev_buffer_get == EV_QUEUE) {
|
||||
+ intr->ev_buffer_get = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_irq) {
|
||||
- xhci_intr_raise(xhci);
|
||||
+ xhci_intr_raise(xhci, v);
|
||||
}
|
||||
|
||||
- if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) {
|
||||
+ if (intr->er_full && intr->ev_buffer_put == intr->ev_buffer_get) {
|
||||
DPRINTF("xhci_events_update(): event ring no longer full\n");
|
||||
- xhci->er_full = 0;
|
||||
+ intr->er_full = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
-static void xhci_event(XHCIState *xhci, XHCIEvent *event)
|
||||
+static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
|
||||
{
|
||||
+ XHCIInterrupter *intr = &xhci->intr[v];
|
||||
dma_addr_t erdp;
|
||||
unsigned int dp_idx;
|
||||
|
||||
- if (xhci->er_full) {
|
||||
+ if (intr->er_full) {
|
||||
DPRINTF("xhci_event(): ER full, queueing\n");
|
||||
- if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
|
||||
+ if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
|
||||
fprintf(stderr, "xhci: event queue full, dropping event!\n");
|
||||
return;
|
||||
}
|
||||
- xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
|
||||
- if (xhci->ev_buffer_put == EV_QUEUE) {
|
||||
- xhci->ev_buffer_put = 0;
|
||||
+ intr->ev_buffer[intr->ev_buffer_put++] = *event;
|
||||
+ if (intr->ev_buffer_put == EV_QUEUE) {
|
||||
+ intr->ev_buffer_put = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
- erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
|
||||
- if (erdp < xhci->er_start ||
|
||||
- erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
|
||||
+ erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
|
||||
+ if (erdp < intr->er_start ||
|
||||
+ erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
|
||||
fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
|
||||
- fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n",
|
||||
- xhci->er_start, xhci->er_size);
|
||||
+ fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
|
||||
+ v, intr->er_start, intr->er_size);
|
||||
xhci_die(xhci);
|
||||
return;
|
||||
}
|
||||
|
||||
- dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
|
||||
- assert(dp_idx < xhci->er_size);
|
||||
+ dp_idx = (erdp - intr->er_start) / TRB_SIZE;
|
||||
+ assert(dp_idx < intr->er_size);
|
||||
|
||||
- if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) {
|
||||
+ if ((intr->er_ep_idx+1) % intr->er_size == dp_idx) {
|
||||
DPRINTF("xhci_event(): ER full, queueing\n");
|
||||
#ifndef ER_FULL_HACK
|
||||
XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
|
||||
xhci_write_event(xhci, &full);
|
||||
#endif
|
||||
- xhci->er_full = 1;
|
||||
- if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
|
||||
+ intr->er_full = 1;
|
||||
+ if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
|
||||
fprintf(stderr, "xhci: event queue full, dropping event!\n");
|
||||
return;
|
||||
}
|
||||
- xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
|
||||
- if (xhci->ev_buffer_put == EV_QUEUE) {
|
||||
- xhci->ev_buffer_put = 0;
|
||||
+ intr->ev_buffer[intr->ev_buffer_put++] = *event;
|
||||
+ if (intr->ev_buffer_put == EV_QUEUE) {
|
||||
+ intr->ev_buffer_put = 0;
|
||||
}
|
||||
} else {
|
||||
- xhci_write_event(xhci, event);
|
||||
+ xhci_write_event(xhci, event, v);
|
||||
}
|
||||
|
||||
- xhci_intr_raise(xhci);
|
||||
+ xhci_intr_raise(xhci, v);
|
||||
}
|
||||
|
||||
static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
|
||||
@@ -939,17 +947,18 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
|
||||
}
|
||||
}
|
||||
|
||||
-static void xhci_er_reset(XHCIState *xhci)
|
||||
+static void xhci_er_reset(XHCIState *xhci, int v)
|
||||
{
|
||||
+ XHCIInterrupter *intr = &xhci->intr[v];
|
||||
XHCIEvRingSeg seg;
|
||||
|
||||
/* cache the (sole) event ring segment location */
|
||||
- if (xhci->erstsz != 1) {
|
||||
- fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz);
|
||||
+ if (intr->erstsz != 1) {
|
||||
+ fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", intr->erstsz);
|
||||
xhci_die(xhci);
|
||||
return;
|
||||
}
|
||||
- dma_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high);
|
||||
+ dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high);
|
||||
pci_dma_read(&xhci->pci_dev, erstba, &seg, sizeof(seg));
|
||||
le32_to_cpus(&seg.addr_low);
|
||||
le32_to_cpus(&seg.addr_high);
|
||||
@@ -959,15 +968,15 @@ static void xhci_er_reset(XHCIState *xhci)
|
||||
xhci_die(xhci);
|
||||
return;
|
||||
}
|
||||
- xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
|
||||
- xhci->er_size = seg.size;
|
||||
+ intr->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
|
||||
+ intr->er_size = seg.size;
|
||||
|
||||
- xhci->er_ep_idx = 0;
|
||||
- xhci->er_pcs = 1;
|
||||
- xhci->er_full = 0;
|
||||
+ intr->er_ep_idx = 0;
|
||||
+ intr->er_pcs = 1;
|
||||
+ intr->er_full = 0;
|
||||
|
||||
- DPRINTF("xhci: event ring:" DMA_ADDR_FMT " [%d]\n",
|
||||
- xhci->er_start, xhci->er_size);
|
||||
+ DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n",
|
||||
+ v, intr->er_start, intr->er_size);
|
||||
}
|
||||
|
||||
static void xhci_run(XHCIState *xhci)
|
||||
@@ -1368,7 +1377,7 @@ static void xhci_xfer_report(XHCITransfer *xfer)
|
||||
DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length);
|
||||
edtla = 0;
|
||||
}
|
||||
- xhci_event(xhci, &event);
|
||||
+ xhci_event(xhci, &event, 0 /* FIXME */);
|
||||
reported = 1;
|
||||
if (xfer->status != CC_SUCCESS) {
|
||||
return;
|
||||
@@ -2246,7 +2255,7 @@ static void xhci_process_commands(XHCIState *xhci)
|
||||
break;
|
||||
}
|
||||
event.slotid = slotid;
|
||||
- xhci_event(xhci, &event);
|
||||
+ xhci_event(xhci, &event, 0 /* FIXME */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2276,7 +2285,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
|
||||
port->portsc |= PORTSC_CSC;
|
||||
XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
|
||||
port->portnr << 24};
|
||||
- xhci_event(xhci, &ev);
|
||||
+ xhci_event(xhci, &ev, 0 /* FIXME */);
|
||||
DPRINTF("xhci: port change event for port %d\n", port->portnr);
|
||||
}
|
||||
}
|
||||
@@ -2309,20 +2318,22 @@ static void xhci_reset(DeviceState *dev)
|
||||
xhci_update_port(xhci, xhci->ports + i, 0);
|
||||
}
|
||||
|
||||
- xhci->iman = 0;
|
||||
- xhci->imod = 0;
|
||||
- xhci->erstsz = 0;
|
||||
- xhci->erstba_low = 0;
|
||||
- xhci->erstba_high = 0;
|
||||
- xhci->erdp_low = 0;
|
||||
- xhci->erdp_high = 0;
|
||||
- xhci->msix_used = 0;
|
||||
+ for (i = 0; i < MAXINTRS; i++) {
|
||||
+ xhci->intr[i].iman = 0;
|
||||
+ xhci->intr[i].imod = 0;
|
||||
+ xhci->intr[i].erstsz = 0;
|
||||
+ xhci->intr[i].erstba_low = 0;
|
||||
+ xhci->intr[i].erstba_high = 0;
|
||||
+ xhci->intr[i].erdp_low = 0;
|
||||
+ xhci->intr[i].erdp_high = 0;
|
||||
+ xhci->intr[i].msix_used = 0;
|
||||
|
||||
- xhci->er_ep_idx = 0;
|
||||
- xhci->er_pcs = 1;
|
||||
- xhci->er_full = 0;
|
||||
- xhci->ev_buffer_put = 0;
|
||||
- xhci->ev_buffer_get = 0;
|
||||
+ xhci->intr[i].er_ep_idx = 0;
|
||||
+ xhci->intr[i].er_pcs = 1;
|
||||
+ xhci->intr[i].er_full = 0;
|
||||
+ xhci->intr[i].ev_buffer_put = 0;
|
||||
+ xhci->intr[i].ev_buffer_get = 0;
|
||||
+ }
|
||||
|
||||
xhci->mfindex_start = qemu_get_clock_ns(vm_clock);
|
||||
xhci_mfwrap_update(xhci);
|
||||
@@ -2553,7 +2564,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) {
|
||||
XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED};
|
||||
xhci->crcr_low &= ~CRCR_CRR;
|
||||
- xhci_event(xhci, &event);
|
||||
+ xhci_event(xhci, &event, 0 /* FIXME */);
|
||||
DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
|
||||
} else {
|
||||
dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
|
||||
@@ -2577,6 +2588,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
|
||||
static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
{
|
||||
+ XHCIInterrupter *intr = &xhci->intr[0];
|
||||
uint32_t ret;
|
||||
|
||||
switch (reg) {
|
||||
@@ -2584,25 +2596,25 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
ret = xhci_mfindex_get(xhci) & 0x3fff;
|
||||
break;
|
||||
case 0x20: /* IMAN */
|
||||
- ret = xhci->iman;
|
||||
+ ret = intr->iman;
|
||||
break;
|
||||
case 0x24: /* IMOD */
|
||||
- ret = xhci->imod;
|
||||
+ ret = intr->imod;
|
||||
break;
|
||||
case 0x28: /* ERSTSZ */
|
||||
- ret = xhci->erstsz;
|
||||
+ ret = intr->erstsz;
|
||||
break;
|
||||
case 0x30: /* ERSTBA low */
|
||||
- ret = xhci->erstba_low;
|
||||
+ ret = intr->erstba_low;
|
||||
break;
|
||||
case 0x34: /* ERSTBA high */
|
||||
- ret = xhci->erstba_high;
|
||||
+ ret = intr->erstba_high;
|
||||
break;
|
||||
case 0x38: /* ERDP low */
|
||||
- ret = xhci->erdp_low;
|
||||
+ ret = intr->erdp_low;
|
||||
break;
|
||||
case 0x3c: /* ERDP high */
|
||||
- ret = xhci->erdp_high;
|
||||
+ ret = intr->erdp_high;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
|
||||
@@ -2615,42 +2627,43 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
|
||||
static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
{
|
||||
+ XHCIInterrupter *intr = &xhci->intr[0];
|
||||
trace_usb_xhci_runtime_write(reg, val);
|
||||
|
||||
switch (reg) {
|
||||
case 0x20: /* IMAN */
|
||||
if (val & IMAN_IP) {
|
||||
- xhci->iman &= ~IMAN_IP;
|
||||
+ intr->iman &= ~IMAN_IP;
|
||||
}
|
||||
- xhci->iman &= ~IMAN_IE;
|
||||
- xhci->iman |= val & IMAN_IE;
|
||||
+ intr->iman &= ~IMAN_IE;
|
||||
+ intr->iman |= val & IMAN_IE;
|
||||
xhci_intx_update(xhci);
|
||||
- xhci_msix_update(xhci);
|
||||
+ xhci_msix_update(xhci, 0);
|
||||
break;
|
||||
case 0x24: /* IMOD */
|
||||
- xhci->imod = val;
|
||||
+ intr->imod = val;
|
||||
break;
|
||||
case 0x28: /* ERSTSZ */
|
||||
- xhci->erstsz = val & 0xffff;
|
||||
+ intr->erstsz = val & 0xffff;
|
||||
break;
|
||||
case 0x30: /* ERSTBA low */
|
||||
/* XXX NEC driver bug: it doesn't align this to 64 bytes
|
||||
- xhci->erstba_low = val & 0xffffffc0; */
|
||||
- xhci->erstba_low = val & 0xfffffff0;
|
||||
+ intr->erstba_low = val & 0xffffffc0; */
|
||||
+ intr->erstba_low = val & 0xfffffff0;
|
||||
break;
|
||||
case 0x34: /* ERSTBA high */
|
||||
- xhci->erstba_high = val;
|
||||
- xhci_er_reset(xhci);
|
||||
+ intr->erstba_high = val;
|
||||
+ xhci_er_reset(xhci, 0);
|
||||
break;
|
||||
case 0x38: /* ERDP low */
|
||||
if (val & ERDP_EHB) {
|
||||
- xhci->erdp_low &= ~ERDP_EHB;
|
||||
+ intr->erdp_low &= ~ERDP_EHB;
|
||||
}
|
||||
- xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB);
|
||||
+ intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB);
|
||||
break;
|
||||
case 0x3c: /* ERDP high */
|
||||
- xhci->erdp_high = val;
|
||||
- xhci_events_update(xhci);
|
||||
+ intr->erdp_high = val;
|
||||
+ xhci_events_update(xhci, 0);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
|
||||
@@ -2780,7 +2793,7 @@ static void xhci_wakeup(USBPort *usbport)
|
||||
return;
|
||||
}
|
||||
port->portsc |= PORTSC_PLC;
|
||||
- xhci_event(xhci, &ev);
|
||||
+ xhci_event(xhci, &ev, 0 /* FIXME */);
|
||||
}
|
||||
|
||||
static void xhci_complete(USBPort *port, USBPacket *packet)
|
||||
diff --git a/trace-events b/trace-events
|
||||
index 8589ca4..b25ae1c 100644
|
||||
--- a/trace-events
|
||||
+++ b/trace-events
|
||||
@@ -316,7 +316,7 @@ usb_xhci_irq_msi(uint32_t nr) "nr %d"
|
||||
usb_xhci_irq_msix(uint32_t nr) "nr %d"
|
||||
usb_xhci_irq_msix_use(uint32_t nr) "nr %d"
|
||||
usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d"
|
||||
-usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
+usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
|
||||
usb_xhci_slot_disable(uint32_t slotid) "slotid %d"
|
||||
--
|
||||
1.7.12
|
||||
|
159
0350-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch
Normal file
159
0350-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch
Normal file
@ -0,0 +1,159 @@
|
||||
From 8bbd489bb885f5799ebbc108022eee3b2d5a1682 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 30 Aug 2012 17:15:12 +0200
|
||||
Subject: [PATCH 350/366] xhci: prepare xhci_runtime_{read,write} for multiple
|
||||
interrupters
|
||||
|
||||
Prepare xhci runtime register access function for multiple interrupters.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 100 +++++++++++++++++++++++++++++++-----------------------
|
||||
1 file changed, 57 insertions(+), 43 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index ddc3825..68a19ab 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -2588,37 +2588,43 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
|
||||
static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
{
|
||||
- XHCIInterrupter *intr = &xhci->intr[0];
|
||||
- uint32_t ret;
|
||||
+ uint32_t ret = 0;
|
||||
|
||||
- switch (reg) {
|
||||
- case 0x00: /* MFINDEX */
|
||||
- ret = xhci_mfindex_get(xhci) & 0x3fff;
|
||||
- break;
|
||||
- case 0x20: /* IMAN */
|
||||
- ret = intr->iman;
|
||||
- break;
|
||||
- case 0x24: /* IMOD */
|
||||
- ret = intr->imod;
|
||||
- break;
|
||||
- case 0x28: /* ERSTSZ */
|
||||
- ret = intr->erstsz;
|
||||
- break;
|
||||
- case 0x30: /* ERSTBA low */
|
||||
- ret = intr->erstba_low;
|
||||
- break;
|
||||
- case 0x34: /* ERSTBA high */
|
||||
- ret = intr->erstba_high;
|
||||
- break;
|
||||
- case 0x38: /* ERDP low */
|
||||
- ret = intr->erdp_low;
|
||||
- break;
|
||||
- case 0x3c: /* ERDP high */
|
||||
- ret = intr->erdp_high;
|
||||
- break;
|
||||
- default:
|
||||
- fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
|
||||
- ret = 0;
|
||||
+ if (reg < 0x20) {
|
||||
+ switch (reg) {
|
||||
+ case 0x00: /* MFINDEX */
|
||||
+ ret = xhci_mfindex_get(xhci) & 0x3fff;
|
||||
+ break;
|
||||
+ default:
|
||||
+ fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ int v = (reg - 0x20) / 0x20;
|
||||
+ XHCIInterrupter *intr = &xhci->intr[v];
|
||||
+ switch (reg & 0x1f) {
|
||||
+ case 0x00: /* IMAN */
|
||||
+ ret = intr->iman;
|
||||
+ break;
|
||||
+ case 0x04: /* IMOD */
|
||||
+ ret = intr->imod;
|
||||
+ break;
|
||||
+ case 0x08: /* ERSTSZ */
|
||||
+ ret = intr->erstsz;
|
||||
+ break;
|
||||
+ case 0x10: /* ERSTBA low */
|
||||
+ ret = intr->erstba_low;
|
||||
+ break;
|
||||
+ case 0x14: /* ERSTBA high */
|
||||
+ ret = intr->erstba_high;
|
||||
+ break;
|
||||
+ case 0x18: /* ERDP low */
|
||||
+ ret = intr->erdp_low;
|
||||
+ break;
|
||||
+ case 0x1c: /* ERDP high */
|
||||
+ ret = intr->erdp_high;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
|
||||
trace_usb_xhci_runtime_read(reg, ret);
|
||||
@@ -2627,43 +2633,51 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
|
||||
static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
{
|
||||
- XHCIInterrupter *intr = &xhci->intr[0];
|
||||
+ int v = (reg - 0x20) / 0x20;
|
||||
+ XHCIInterrupter *intr = &xhci->intr[v];
|
||||
trace_usb_xhci_runtime_write(reg, val);
|
||||
|
||||
- switch (reg) {
|
||||
- case 0x20: /* IMAN */
|
||||
+ if (reg < 0x20) {
|
||||
+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ switch (reg & 0x1f) {
|
||||
+ case 0x00: /* IMAN */
|
||||
if (val & IMAN_IP) {
|
||||
intr->iman &= ~IMAN_IP;
|
||||
}
|
||||
intr->iman &= ~IMAN_IE;
|
||||
intr->iman |= val & IMAN_IE;
|
||||
- xhci_intx_update(xhci);
|
||||
- xhci_msix_update(xhci, 0);
|
||||
+ if (v == 0) {
|
||||
+ xhci_intx_update(xhci);
|
||||
+ }
|
||||
+ xhci_msix_update(xhci, v);
|
||||
break;
|
||||
- case 0x24: /* IMOD */
|
||||
+ case 0x04: /* IMOD */
|
||||
intr->imod = val;
|
||||
break;
|
||||
- case 0x28: /* ERSTSZ */
|
||||
+ case 0x08: /* ERSTSZ */
|
||||
intr->erstsz = val & 0xffff;
|
||||
break;
|
||||
- case 0x30: /* ERSTBA low */
|
||||
+ case 0x10: /* ERSTBA low */
|
||||
/* XXX NEC driver bug: it doesn't align this to 64 bytes
|
||||
intr->erstba_low = val & 0xffffffc0; */
|
||||
intr->erstba_low = val & 0xfffffff0;
|
||||
break;
|
||||
- case 0x34: /* ERSTBA high */
|
||||
+ case 0x14: /* ERSTBA high */
|
||||
intr->erstba_high = val;
|
||||
- xhci_er_reset(xhci, 0);
|
||||
+ xhci_er_reset(xhci, v);
|
||||
break;
|
||||
- case 0x38: /* ERDP low */
|
||||
+ case 0x18: /* ERDP low */
|
||||
if (val & ERDP_EHB) {
|
||||
intr->erdp_low &= ~ERDP_EHB;
|
||||
}
|
||||
intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB);
|
||||
break;
|
||||
- case 0x3c: /* ERDP high */
|
||||
+ case 0x1c: /* ERDP high */
|
||||
intr->erdp_high = val;
|
||||
- xhci_events_update(xhci, 0);
|
||||
+ xhci_events_update(xhci, v);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
|
||||
--
|
||||
1.7.12
|
||||
|
93
0351-xhci-pick-target-interrupter.patch
Normal file
93
0351-xhci-pick-target-interrupter.patch
Normal file
@ -0,0 +1,93 @@
|
||||
From 11ba203517cc28be513ac31c12762c4519e98ee5 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 31 Aug 2012 15:30:51 +0200
|
||||
Subject: [PATCH 351/366] xhci: pick target interrupter
|
||||
|
||||
Pick the correct interrupter when queuing an event.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 22 ++++++++++++++++------
|
||||
1 file changed, 16 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 68a19ab..d6ab0c6 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -264,6 +264,10 @@ typedef enum TRBCCode {
|
||||
|
||||
#define TRB_LK_TC (1<<1)
|
||||
|
||||
+#define TRB_INTR_SHIFT 22
|
||||
+#define TRB_INTR_MASK 0x3ff
|
||||
+#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK)
|
||||
+
|
||||
#define EP_TYPE_MASK 0x7
|
||||
#define EP_TYPE_SHIFT 3
|
||||
|
||||
@@ -806,10 +810,16 @@ static void xhci_events_update(XHCIState *xhci, int v)
|
||||
|
||||
static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
|
||||
{
|
||||
- XHCIInterrupter *intr = &xhci->intr[v];
|
||||
+ XHCIInterrupter *intr;
|
||||
dma_addr_t erdp;
|
||||
unsigned int dp_idx;
|
||||
|
||||
+ if (v >= MAXINTRS) {
|
||||
+ DPRINTF("intr nr out of range (%d >= %d)\n", v, MAXINTRS);
|
||||
+ return;
|
||||
+ }
|
||||
+ intr = &xhci->intr[v];
|
||||
+
|
||||
if (intr->er_full) {
|
||||
DPRINTF("xhci_event(): ER full, queueing\n");
|
||||
if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
|
||||
@@ -1377,7 +1387,7 @@ static void xhci_xfer_report(XHCITransfer *xfer)
|
||||
DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length);
|
||||
edtla = 0;
|
||||
}
|
||||
- xhci_event(xhci, &event, 0 /* FIXME */);
|
||||
+ xhci_event(xhci, &event, TRB_INTR(*trb));
|
||||
reported = 1;
|
||||
if (xfer->status != CC_SUCCESS) {
|
||||
return;
|
||||
@@ -2255,7 +2265,7 @@ static void xhci_process_commands(XHCIState *xhci)
|
||||
break;
|
||||
}
|
||||
event.slotid = slotid;
|
||||
- xhci_event(xhci, &event, 0 /* FIXME */);
|
||||
+ xhci_event(xhci, &event, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2285,7 +2295,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
|
||||
port->portsc |= PORTSC_CSC;
|
||||
XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
|
||||
port->portnr << 24};
|
||||
- xhci_event(xhci, &ev, 0 /* FIXME */);
|
||||
+ xhci_event(xhci, &ev, 0);
|
||||
DPRINTF("xhci: port change event for port %d\n", port->portnr);
|
||||
}
|
||||
}
|
||||
@@ -2564,7 +2574,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) {
|
||||
XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED};
|
||||
xhci->crcr_low &= ~CRCR_CRR;
|
||||
- xhci_event(xhci, &event, 0 /* FIXME */);
|
||||
+ xhci_event(xhci, &event, 0);
|
||||
DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
|
||||
} else {
|
||||
dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
|
||||
@@ -2807,7 +2817,7 @@ static void xhci_wakeup(USBPort *usbport)
|
||||
return;
|
||||
}
|
||||
port->portsc |= PORTSC_PLC;
|
||||
- xhci_event(xhci, &ev, 0 /* FIXME */);
|
||||
+ xhci_event(xhci, &ev, 0);
|
||||
}
|
||||
|
||||
static void xhci_complete(USBPort *port, USBPacket *packet)
|
||||
--
|
||||
1.7.12
|
||||
|
40
0352-xhci-support-multiple-interrupters.patch
Normal file
40
0352-xhci-support-multiple-interrupters.patch
Normal file
@ -0,0 +1,40 @@
|
||||
From d6d045365af5cef5bc98ad48dcf4172cbe35c7c4 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 4 Sep 2012 12:56:55 +0200
|
||||
Subject: [PATCH 352/366] xhci: support multiple interrupters
|
||||
|
||||
Everything is in place, flip the big switch now
|
||||
and enable support for multiple interrupters.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 6 +-----
|
||||
1 file changed, 1 insertion(+), 5 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index d6ab0c6..55e31ec 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
#define MAXPORTS (MAXPORTS_2+MAXPORTS_3)
|
||||
#define MAXSLOTS MAXPORTS
|
||||
-#define MAXINTRS 1 /* MAXPORTS */
|
||||
+#define MAXINTRS MAXPORTS
|
||||
|
||||
#define TD_QUEUE 24
|
||||
|
||||
@@ -75,10 +75,6 @@
|
||||
# error Increase LEN_REGS
|
||||
#endif
|
||||
|
||||
-#if MAXINTRS > 1
|
||||
-# error TODO: only one interrupter supported
|
||||
-#endif
|
||||
-
|
||||
/* bit definitions */
|
||||
#define USBCMD_RS (1<<0)
|
||||
#define USBCMD_HCRST (1<<1)
|
||||
--
|
||||
1.7.12
|
||||
|
281
0353-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch
Normal file
281
0353-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch
Normal file
@ -0,0 +1,281 @@
|
||||
From e5295db184d2b78a6a779aac019acbf58ed3da5e Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 4 Sep 2012 14:42:20 +0200
|
||||
Subject: [PATCH 353/366] xhci: kill xhci_mem_{read,write} dispatcher
|
||||
functions
|
||||
|
||||
... and register subregions instead, so we offload the dispatching
|
||||
to the the memory subsystem which is designed to handle it.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 140 +++++++++++++++++++++++++++++-------------------------
|
||||
1 file changed, 75 insertions(+), 65 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 55e31ec..500892d 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -404,6 +404,10 @@ struct XHCIState {
|
||||
USBBus bus;
|
||||
qemu_irq irq;
|
||||
MemoryRegion mem;
|
||||
+ MemoryRegion mem_cap;
|
||||
+ MemoryRegion mem_oper;
|
||||
+ MemoryRegion mem_runtime;
|
||||
+ MemoryRegion mem_doorbell;
|
||||
const char *name;
|
||||
unsigned int devaddr;
|
||||
|
||||
@@ -2345,8 +2349,9 @@ static void xhci_reset(DeviceState *dev)
|
||||
xhci_mfwrap_update(xhci);
|
||||
}
|
||||
|
||||
-static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
|
||||
+static uint64_t xhci_cap_read(void *ptr, target_phys_addr_t reg, unsigned size)
|
||||
{
|
||||
+ XHCIState *xhci = ptr;
|
||||
uint32_t ret;
|
||||
|
||||
switch (reg) {
|
||||
@@ -2403,7 +2408,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
|
||||
ret = 0x00000000; /* reserved */
|
||||
break;
|
||||
default:
|
||||
- fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg);
|
||||
+ fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", (int)reg);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
@@ -2484,8 +2489,9 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
-static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg)
|
||||
+static uint64_t xhci_oper_read(void *ptr, target_phys_addr_t reg, unsigned size)
|
||||
{
|
||||
+ XHCIState *xhci = ptr;
|
||||
uint32_t ret;
|
||||
|
||||
if (reg >= 0x400) {
|
||||
@@ -2521,7 +2527,7 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg)
|
||||
ret = xhci->config;
|
||||
break;
|
||||
default:
|
||||
- fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg);
|
||||
+ fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", (int)reg);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
@@ -2529,8 +2535,11 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
+static void xhci_oper_write(void *ptr, target_phys_addr_t reg,
|
||||
+ uint64_t val, unsigned size)
|
||||
{
|
||||
+ XHCIState *xhci = ptr;
|
||||
+
|
||||
if (reg >= 0x400) {
|
||||
xhci_port_write(xhci, reg - 0x400, val);
|
||||
return;
|
||||
@@ -2588,12 +2597,14 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
xhci->config = val & 0xff;
|
||||
break;
|
||||
default:
|
||||
- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
|
||||
+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg);
|
||||
}
|
||||
}
|
||||
|
||||
-static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
+static uint64_t xhci_runtime_read(void *ptr, target_phys_addr_t reg,
|
||||
+ unsigned size)
|
||||
{
|
||||
+ XHCIState *xhci = ptr;
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (reg < 0x20) {
|
||||
@@ -2602,7 +2613,8 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
ret = xhci_mfindex_get(xhci) & 0x3fff;
|
||||
break;
|
||||
default:
|
||||
- fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
|
||||
+ fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n",
|
||||
+ (int)reg);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -2637,14 +2649,16 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
+static void xhci_runtime_write(void *ptr, target_phys_addr_t reg,
|
||||
+ uint64_t val, unsigned size)
|
||||
{
|
||||
+ XHCIState *xhci = ptr;
|
||||
int v = (reg - 0x20) / 0x20;
|
||||
XHCIInterrupter *intr = &xhci->intr[v];
|
||||
trace_usb_xhci_runtime_write(reg, val);
|
||||
|
||||
if (reg < 0x20) {
|
||||
- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
|
||||
+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2686,19 +2700,24 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
xhci_events_update(xhci, v);
|
||||
break;
|
||||
default:
|
||||
- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
|
||||
+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n",
|
||||
+ (int)reg);
|
||||
}
|
||||
}
|
||||
|
||||
-static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg)
|
||||
+static uint64_t xhci_doorbell_read(void *ptr, target_phys_addr_t reg,
|
||||
+ unsigned size)
|
||||
{
|
||||
/* doorbells always read as 0 */
|
||||
trace_usb_xhci_doorbell_read(reg, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
+static void xhci_doorbell_write(void *ptr, target_phys_addr_t reg,
|
||||
+ uint64_t val, unsigned size)
|
||||
{
|
||||
+ XHCIState *xhci = ptr;
|
||||
+
|
||||
trace_usb_xhci_doorbell_write(reg, val);
|
||||
|
||||
if (!xhci_running(xhci)) {
|
||||
@@ -2712,69 +2731,47 @@ static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
if (val == 0) {
|
||||
xhci_process_commands(xhci);
|
||||
} else {
|
||||
- fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", val);
|
||||
+ fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n",
|
||||
+ (uint32_t)val);
|
||||
}
|
||||
} else {
|
||||
if (reg > MAXSLOTS) {
|
||||
- fprintf(stderr, "xhci: bad doorbell %d\n", reg);
|
||||
+ fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg);
|
||||
} else if (val > 31) {
|
||||
- fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", reg, val);
|
||||
+ fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n",
|
||||
+ (int)reg, (uint32_t)val);
|
||||
} else {
|
||||
xhci_kick_ep(xhci, reg, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-static uint64_t xhci_mem_read(void *ptr, target_phys_addr_t addr,
|
||||
- unsigned size)
|
||||
-{
|
||||
- XHCIState *xhci = ptr;
|
||||
-
|
||||
- /* Only aligned reads are allowed on xHCI */
|
||||
- if (addr & 3) {
|
||||
- fprintf(stderr, "xhci_mem_read: Mis-aligned read\n");
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- if (addr < LEN_CAP) {
|
||||
- return xhci_cap_read(xhci, addr);
|
||||
- } else if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) {
|
||||
- return xhci_oper_read(xhci, addr - OFF_OPER);
|
||||
- } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) {
|
||||
- return xhci_runtime_read(xhci, addr - OFF_RUNTIME);
|
||||
- } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) {
|
||||
- return xhci_doorbell_read(xhci, addr - OFF_DOORBELL);
|
||||
- } else {
|
||||
- fprintf(stderr, "xhci_mem_read: Bad offset %x\n", (int)addr);
|
||||
- return 0;
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static void xhci_mem_write(void *ptr, target_phys_addr_t addr,
|
||||
- uint64_t val, unsigned size)
|
||||
-{
|
||||
- XHCIState *xhci = ptr;
|
||||
+static const MemoryRegionOps xhci_cap_ops = {
|
||||
+ .read = xhci_cap_read,
|
||||
+ .valid.min_access_size = 4,
|
||||
+ .valid.max_access_size = 4,
|
||||
+ .endianness = DEVICE_LITTLE_ENDIAN,
|
||||
+};
|
||||
|
||||
- /* Only aligned writes are allowed on xHCI */
|
||||
- if (addr & 3) {
|
||||
- fprintf(stderr, "xhci_mem_write: Mis-aligned write\n");
|
||||
- return;
|
||||
- }
|
||||
+static const MemoryRegionOps xhci_oper_ops = {
|
||||
+ .read = xhci_oper_read,
|
||||
+ .write = xhci_oper_write,
|
||||
+ .valid.min_access_size = 4,
|
||||
+ .valid.max_access_size = 4,
|
||||
+ .endianness = DEVICE_LITTLE_ENDIAN,
|
||||
+};
|
||||
|
||||
- if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) {
|
||||
- xhci_oper_write(xhci, addr - OFF_OPER, val);
|
||||
- } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) {
|
||||
- xhci_runtime_write(xhci, addr - OFF_RUNTIME, val);
|
||||
- } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) {
|
||||
- xhci_doorbell_write(xhci, addr - OFF_DOORBELL, val);
|
||||
- } else {
|
||||
- fprintf(stderr, "xhci_mem_write: Bad offset %x\n", (int)addr);
|
||||
- }
|
||||
-}
|
||||
+static const MemoryRegionOps xhci_runtime_ops = {
|
||||
+ .read = xhci_runtime_read,
|
||||
+ .write = xhci_runtime_write,
|
||||
+ .valid.min_access_size = 4,
|
||||
+ .valid.max_access_size = 4,
|
||||
+ .endianness = DEVICE_LITTLE_ENDIAN,
|
||||
+};
|
||||
|
||||
-static const MemoryRegionOps xhci_mem_ops = {
|
||||
- .read = xhci_mem_read,
|
||||
- .write = xhci_mem_write,
|
||||
+static const MemoryRegionOps xhci_doorbell_ops = {
|
||||
+ .read = xhci_doorbell_read,
|
||||
+ .write = xhci_doorbell_write,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
@@ -2940,8 +2937,21 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
|
||||
|
||||
xhci->irq = xhci->pci_dev.irq[0];
|
||||
|
||||
- memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci,
|
||||
- "xhci", LEN_REGS);
|
||||
+ memory_region_init(&xhci->mem, "xhci", LEN_REGS);
|
||||
+ memory_region_init_io(&xhci->mem_cap, &xhci_cap_ops, xhci,
|
||||
+ "capabilities", LEN_CAP);
|
||||
+ memory_region_init_io(&xhci->mem_oper, &xhci_oper_ops, xhci,
|
||||
+ "operational", 0x400 + 0x10 * xhci->numports);
|
||||
+ memory_region_init_io(&xhci->mem_runtime, &xhci_runtime_ops, xhci,
|
||||
+ "runtime", LEN_RUNTIME);
|
||||
+ memory_region_init_io(&xhci->mem_doorbell, &xhci_doorbell_ops, xhci,
|
||||
+ "doorbell", LEN_DOORBELL);
|
||||
+
|
||||
+ memory_region_add_subregion(&xhci->mem, 0, &xhci->mem_cap);
|
||||
+ memory_region_add_subregion(&xhci->mem, OFF_OPER, &xhci->mem_oper);
|
||||
+ memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime);
|
||||
+ memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell);
|
||||
+
|
||||
pci_register_bar(&xhci->pci_dev, 0,
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
|
||||
&xhci->mem);
|
||||
--
|
||||
1.7.12
|
||||
|
32
0354-xhci-allow-bytewise-capability-register-reads.patch
Normal file
32
0354-xhci-allow-bytewise-capability-register-reads.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 25968a7c7947b7e215e351b159a5f4ebf4609aab Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 4 Sep 2012 14:48:03 +0200
|
||||
Subject: [PATCH 354/366] xhci: allow bytewise capability register reads
|
||||
|
||||
Some guests need this according to
|
||||
Alejandro Martinez Ruiz <alex@securiforest.com>
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/hcd-xhci.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
|
||||
index 500892d..2918e64 100644
|
||||
--- a/hw/usb/hcd-xhci.c
|
||||
+++ b/hw/usb/hcd-xhci.c
|
||||
@@ -2748,8 +2748,10 @@ static void xhci_doorbell_write(void *ptr, target_phys_addr_t reg,
|
||||
|
||||
static const MemoryRegionOps xhci_cap_ops = {
|
||||
.read = xhci_cap_read,
|
||||
- .valid.min_access_size = 4,
|
||||
+ .valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
+ .impl.min_access_size = 4,
|
||||
+ .impl.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
--
|
||||
1.7.12
|
||||
|
367
0355-ehci-switch-to-new-style-memory-ops.patch
Normal file
367
0355-ehci-switch-to-new-style-memory-ops.patch
Normal file
@ -0,0 +1,367 @@
|
||||
From 538ee859ae415782e5be3b4a07e7db655cf70aa2 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
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 <david@gibson.dropbear.id.au>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
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
|
||||
|
33
0356-xhci-drop-unused-wlength.patch
Normal file
33
0356-xhci-drop-unused-wlength.patch
Normal file
@ -0,0 +1,33 @@
|
||||
From 0b32fd99ab948db3b4cac32562272095a2594f4c Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Thu, 6 Sep 2012 11:55:06 +0200
|
||||
Subject: [PATCH 356/366] xhci: drop unused wlength
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,37 @@
|
||||
From 487e24442148aa659a53f69db394642a7d93c3c6 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
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 <kraxel@redhat.com>
|
||||
---
|
||||
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
|
||||
|
101
0358-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch
Normal file
101
0358-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch
Normal file
@ -0,0 +1,101 @@
|
||||
From 833eeda8129b2cf4955a34600b60c01e00652526 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
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 <hdegoede@redhat.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,66 @@
|
||||
From fec70ddafe1632f40608ef6917760a7f946f278a Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
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 <hdegoede@redhat.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,49 @@
|
||||
From d2901e4798cb106d5b265aa4e3ae05c06bf2bd1c Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
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 <hdegoede@redhat.com>
|
||||
---
|
||||
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
|
||||
|
43
0361-usb-Migrate-over-device-speed-and-speedmask.patch
Normal file
43
0361-usb-Migrate-over-device-speed-and-speedmask.patch
Normal file
@ -0,0 +1,43 @@
|
||||
From 6ba840c192897029895930a504527d4350b88d26 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Thu, 6 Sep 2012 15:34:19 +0200
|
||||
Subject: [PATCH 361/366] usb: Migrate over device speed and speedmask
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/usb.h | 4 ++--
|
||||
hw/usb/bus.c | 2 ++
|
||||
2 files changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/usb.h b/hw/usb.h
|
||||
index 48c8926..918af99 100644
|
||||
--- a/hw/usb.h
|
||||
+++ b/hw/usb.h
|
||||
@@ -204,9 +204,9 @@ struct USBDevice {
|
||||
uint32_t flags;
|
||||
|
||||
/* Actual connected speed */
|
||||
- int speed;
|
||||
+ int32_t speed;
|
||||
/* Supported speeds, not in info because it may be variable (hostdevs) */
|
||||
- int speedmask;
|
||||
+ int32_t speedmask;
|
||||
uint8_t addr;
|
||||
char product_desc[32];
|
||||
int auto_attach;
|
||||
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
|
||||
index b649360..223c1df 100644
|
||||
--- a/hw/usb/bus.c
|
||||
+++ b/hw/usb/bus.c
|
||||
@@ -55,6 +55,8 @@ const VMStateDescription vmstate_usb_device = {
|
||||
.minimum_version_id = 1,
|
||||
.post_load = usb_device_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
+ VMSTATE_INT32(speed, USBDevice),
|
||||
+ VMSTATE_INT32(speedmask, USBDevice),
|
||||
VMSTATE_UINT8(addr, USBDevice),
|
||||
VMSTATE_INT32(state, USBDevice),
|
||||
VMSTATE_INT32(remote_wakeup, USBDevice),
|
||||
--
|
||||
1.7.12
|
||||
|
184
0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch
Normal file
184
0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch
Normal file
@ -0,0 +1,184 @@
|
||||
From 4d7d1b57fa5d3a950818e5dee459aefa4dc6ae27 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 4 Sep 2012 14:18:34 +0200
|
||||
Subject: [PATCH 362/366] usb-redir: Change cancelled packet code into a
|
||||
generic packet-id queue
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
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
|
||||
|
119
0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch
Normal file
119
0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch
Normal file
@ -0,0 +1,119 @@
|
||||
From 4e0fcd7ef28b0ee06fd6f9d736dbdccefcf0b2bf Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 4 Sep 2012 17:03:54 +0200
|
||||
Subject: [PATCH 363/366] 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 <hdegoede@redhat,com>
|
||||
---
|
||||
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
|
||||
|
38
0364-usb-redir-Store-max_packet_size-in-endp_data.patch
Normal file
38
0364-usb-redir-Store-max_packet_size-in-endp_data.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From 372d6c55bbe5fb092ff9e96c72ff53bfd10fdede Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Thu, 6 Sep 2012 20:52:36 +0200
|
||||
Subject: [PATCH 364/366] 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 <hdegoede@redhat.com>
|
||||
---
|
||||
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
|
||||
|
411
0365-usb-redir-Add-support-for-migration.patch
Normal file
411
0365-usb-redir-Add-support-for-migration.patch
Normal file
@ -0,0 +1,411 @@
|
||||
From e6a683c844845c53bcf14f9fb3ea175331eaca0c Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Wed, 5 Sep 2012 09:21:44 +0200
|
||||
Subject: [PATCH 365/366] usb-redir: Add support for migration
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 331 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 328 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index d8568ae..8dbb722 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,304 @@ 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;
|
||||
+
|
||||
+ 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 +1874,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
|
||||
|
54
0366-usb-redir-Add-chardev-open-close-debug-logging.patch
Normal file
54
0366-usb-redir-Add-chardev-open-close-debug-logging.patch
Normal file
@ -0,0 +1,54 @@
|
||||
From 93691f50a5200651f22e698cc29be0b1a020f5c5 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Wed, 5 Sep 2012 15:56:57 +0200
|
||||
Subject: [PATCH 366/366] usb-redir: Add chardev open / close debug logging
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/usb/redirect.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
|
||||
index 8dbb722..95a2167 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
|
||||
|
197
qemu.spec
197
qemu.spec
@ -34,12 +34,10 @@
|
||||
%bcond_without fdt # enabled
|
||||
%endif
|
||||
|
||||
%global rcversion rc1
|
||||
|
||||
Summary: QEMU is a FAST! processor emulator
|
||||
Name: qemu
|
||||
Version: 1.2.0
|
||||
Release: 0.5.%{rcversion}%{?dist}
|
||||
Release: 1%{?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
|
||||
@ -55,7 +53,10 @@ ExclusiveArch: x86_64
|
||||
%define _smp_mflags %{nil}
|
||||
%endif
|
||||
|
||||
Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}-%{rcversion}.tar.gz
|
||||
# This is generated from the git qemu-kvm-1.2.0 tag, replace with proper
|
||||
# upstream tarbal once available
|
||||
Source0: qemu-kvm-%{version}.tar.gz
|
||||
#Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}.tar.gz
|
||||
|
||||
Source1: qemu.binfmt
|
||||
|
||||
@ -98,6 +99,96 @@ Patch111: 0111-usb-redir-Add-flow-control-support.patch
|
||||
Patch112: 0112-virtio-serial-bus-replay-guest_open-on-migration.patch
|
||||
Patch113: 0113-char-Disable-write-callback-if-throttled-chardev-is-.patch
|
||||
|
||||
# Spice features from upstream master: seamless migration & dynamic monitors
|
||||
Patch201: 0201-spice-abort-on-invalid-streaming-cmdline-params.patch
|
||||
Patch202: 0202-spice-notify-spice-server-on-vm-start-stop.patch
|
||||
Patch203: 0203-spice-notify-on-vm-state-change-only-via-spice_serve.patch
|
||||
Patch204: 0204-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch
|
||||
Patch205: 0205-spice-add-migrated-flag-to-spice-info.patch
|
||||
Patch206: 0206-spice-adding-seamless-migration-option-to-the-comman.patch
|
||||
Patch207: 0207-spice-increase-the-verbosity-of-spice-section-in-qem.patch
|
||||
Patch208: 0208-qxl-update_area_io-guest_bug-on-invalid-parameters.patch
|
||||
Patch209: 0209-qxl-disallow-unknown-revisions.patch
|
||||
Patch210: 0210-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch
|
||||
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
|
||||
|
||||
# Ugh, ton of USB bugfixes / preparation patches for usb-redir
|
||||
# live-migration which did not make 1.2.0 :|
|
||||
# All are in upstream master so can be dropped next qemu release
|
||||
Patch0301: 0301-usb-controllers-do-not-need-to-check-for-babble-them.patch
|
||||
Patch0302: 0302-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch
|
||||
Patch0303: 0303-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch
|
||||
Patch0304: 0304-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch
|
||||
Patch0305: 0305-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch
|
||||
Patch0306: 0306-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch
|
||||
Patch0307: 0307-ehci-Update-copyright-headers-to-reflect-recent-work.patch
|
||||
Patch0308: 0308-ehci-Properly-cleanup-packets-on-cancel.patch
|
||||
Patch0309: 0309-ehci-Properly-report-completed-but-not-yet-processed.patch
|
||||
Patch0310: 0310-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch
|
||||
Patch0311: 0311-ehci-trace-guest-bugs.patch
|
||||
Patch0312: 0312-ehci-add-doorbell-trace-events.patch
|
||||
Patch0313: 0313-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch
|
||||
Patch0314: 0314-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch
|
||||
Patch0315: 0315-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch
|
||||
Patch0316: 0316-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch
|
||||
Patch0317: 0317-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch
|
||||
Patch0318: 0318-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch
|
||||
Patch0319: 0319-usb-redir-Get-rid-of-async-struct-get-member.patch
|
||||
Patch0320: 0320-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch
|
||||
Patch0321: 0321-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch
|
||||
Patch0322: 0322-usb-redir-Move-to-core-packet-id-and-queue-handling.patch
|
||||
Patch0323: 0323-usb-redir-Return-babble-when-getting-more-bulk-data-.patch
|
||||
Patch0324: 0324-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch
|
||||
Patch0325: 0325-usb-redir-Set-ep-max_packet_size-if-available.patch
|
||||
Patch0326: 0326-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch
|
||||
Patch0327: 0327-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch
|
||||
Patch0328: 0328-usb-redir-Enable-pipelining-for-bulk-endpoints.patch
|
||||
Patch0329: 0329-Better-name-usb-braille-device.patch
|
||||
Patch0330: 0330-usb-audio-fix-usb-version.patch
|
||||
Patch0331: 0331-xhci-rip-out-background-transfer-code.patch
|
||||
Patch0332: 0332-xhci-drop-buffering.patch
|
||||
Patch0333: 0333-xhci-move-device-lookup-into-xhci_setup_packet.patch
|
||||
Patch0334: 0334-xhci-implement-mfindex.patch
|
||||
Patch0335: 0335-xhci-iso-xfer-support.patch
|
||||
Patch0336: 0336-xhci-trace-cc-codes-in-cleartext.patch
|
||||
Patch0337: 0337-xhci-add-trace_usb_xhci_ep_set_dequeue.patch
|
||||
Patch0338: 0338-xhci-fix-runtime-write-tracepoint.patch
|
||||
Patch0339: 0339-xhci-update-register-layout.patch
|
||||
Patch0340: 0340-xhci-update-port-handling.patch
|
||||
Patch0341: 0341-usb3-superspeed-descriptors.patch
|
||||
Patch0342: 0342-usb3-superspeed-endpoint-companion.patch
|
||||
Patch0343: 0343-usb3-bos-decriptor.patch
|
||||
Patch0344: 0344-usb-storage-usb3-support.patch
|
||||
Patch0345: 0345-xhci-fix-cleanup-msi.patch
|
||||
Patch0346: 0346-xhci-rework-interrupt-handling.patch
|
||||
Patch0347: 0347-xhci-add-msix-support.patch
|
||||
Patch0348: 0348-xhci-move-register-update-into-xhci_intr_raise.patch
|
||||
Patch0349: 0349-xhci-add-XHCIInterrupter.patch
|
||||
Patch0350: 0350-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch
|
||||
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
|
||||
|
||||
# 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-Migrate-over-device-speed-and-speedmask.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
|
||||
|
||||
BuildRequires: SDL-devel
|
||||
BuildRequires: zlib-devel
|
||||
BuildRequires: which
|
||||
@ -111,11 +202,11 @@ BuildRequires: pciutils-devel
|
||||
BuildRequires: pulseaudio-libs-devel
|
||||
BuildRequires: ncurses-devel
|
||||
BuildRequires: libattr-devel
|
||||
BuildRequires: usbredir-devel >= 0.4.1
|
||||
BuildRequires: usbredir-devel >= 0.5
|
||||
BuildRequires: texinfo
|
||||
%ifarch %{ix86} x86_64
|
||||
BuildRequires: spice-protocol >= 0.8.1
|
||||
BuildRequires: spice-server-devel >= 0.9.0
|
||||
BuildRequires: spice-protocol >= 0.12.1
|
||||
BuildRequires: spice-server-devel >= 0.11.3
|
||||
BuildRequires: libseccomp-devel >= 1.0.0
|
||||
%endif
|
||||
# For network block driver
|
||||
@ -375,7 +466,7 @@ such as kvm_stat.
|
||||
%endif
|
||||
|
||||
%prep
|
||||
%setup -q -n qemu-kvm-%{version}-%{rcversion}
|
||||
%setup -q -n qemu-kvm-%{version}
|
||||
|
||||
%patch1 -p1
|
||||
%patch2 -p1
|
||||
@ -394,6 +485,90 @@ such as kvm_stat.
|
||||
%patch112 -p1
|
||||
%patch113 -p1
|
||||
|
||||
%patch201 -p1
|
||||
%patch202 -p1
|
||||
%patch203 -p1
|
||||
%patch204 -p1
|
||||
%patch205 -p1
|
||||
%patch206 -p1
|
||||
%patch207 -p1
|
||||
%patch208 -p1
|
||||
%patch209 -p1
|
||||
%patch210 -p1
|
||||
%patch211 -p1
|
||||
%patch212 -p1
|
||||
%patch213 -p1
|
||||
%patch214 -p1
|
||||
%patch215 -p1
|
||||
|
||||
%patch301 -p1
|
||||
%patch302 -p1
|
||||
%patch303 -p1
|
||||
%patch304 -p1
|
||||
%patch305 -p1
|
||||
%patch306 -p1
|
||||
%patch307 -p1
|
||||
%patch308 -p1
|
||||
%patch309 -p1
|
||||
%patch310 -p1
|
||||
%patch311 -p1
|
||||
%patch312 -p1
|
||||
%patch313 -p1
|
||||
%patch314 -p1
|
||||
%patch315 -p1
|
||||
%patch316 -p1
|
||||
%patch317 -p1
|
||||
%patch318 -p1
|
||||
%patch319 -p1
|
||||
%patch320 -p1
|
||||
%patch321 -p1
|
||||
%patch322 -p1
|
||||
%patch323 -p1
|
||||
%patch324 -p1
|
||||
%patch325 -p1
|
||||
%patch326 -p1
|
||||
%patch327 -p1
|
||||
%patch328 -p1
|
||||
%patch329 -p1
|
||||
%patch330 -p1
|
||||
%patch331 -p1
|
||||
%patch332 -p1
|
||||
%patch333 -p1
|
||||
%patch334 -p1
|
||||
%patch335 -p1
|
||||
%patch336 -p1
|
||||
%patch337 -p1
|
||||
%patch338 -p1
|
||||
%patch339 -p1
|
||||
%patch340 -p1
|
||||
%patch341 -p1
|
||||
%patch342 -p1
|
||||
%patch343 -p1
|
||||
%patch344 -p1
|
||||
%patch345 -p1
|
||||
%patch346 -p1
|
||||
%patch347 -p1
|
||||
%patch348 -p1
|
||||
%patch349 -p1
|
||||
%patch350 -p1
|
||||
%patch351 -p1
|
||||
%patch352 -p1
|
||||
%patch353 -p1
|
||||
%patch354 -p1
|
||||
%patch355 -p1
|
||||
%patch356 -p1
|
||||
%patch357 -p1
|
||||
%patch358 -p1
|
||||
%patch359 -p1
|
||||
%patch360 -p1
|
||||
%patch361 -p1
|
||||
%patch362 -p1
|
||||
%patch363 -p1
|
||||
%patch364 -p1
|
||||
%patch365 -p1
|
||||
%patch366 -p1
|
||||
|
||||
|
||||
%build
|
||||
buildarch="i386-softmmu x86_64-softmmu arm-softmmu cris-softmmu \
|
||||
m68k-softmmu mips-softmmu mipsel-softmmu mips64-softmmu \
|
||||
@ -871,6 +1046,12 @@ fi
|
||||
%{_mandir}/man1/qemu-img.1*
|
||||
|
||||
%changelog
|
||||
* Fri Sep 9 2012 Hans de Goede <hdegoede@redhat.com> - 2:1.2.0-1
|
||||
- New upstream release 1.2.0 final
|
||||
- Add support for Spice seamless migration
|
||||
- Add support for Spice dynamic monitors
|
||||
- Add support for usb-redir live migration
|
||||
|
||||
* Tue Sep 04 2012 Adam Jackson <ajax@redhat.com> 1.2.0-0.5.rc1
|
||||
- Flip Requires: ceph >= foo to Conflicts: ceph < foo, so we pull in only the
|
||||
libraries which we need and not the rest of ceph which we don't.
|
||||
|
Loading…
Reference in New Issue
Block a user