mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-23 06:00:49 +00:00
Merge remote-tracking branch 'kraxel/usb.54' into staging
* kraxel/usb.54: uhci: fix uhci_async_cancel_all usb-host: live migration support usb-host: attach only to running guest ehci: tracing improvements usb: restore USBDevice->attached on vmload ehci: add live migration support
This commit is contained in:
commit
b1a6609e75
13
hw/usb/bus.c
13
hw/usb/bus.c
@ -37,10 +37,23 @@ static const TypeInfo usb_bus_info = {
|
||||
static int next_usb_bus = 0;
|
||||
static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
|
||||
|
||||
static int usb_device_post_load(void *opaque, int version_id)
|
||||
{
|
||||
USBDevice *dev = opaque;
|
||||
|
||||
if (dev->state == USB_STATE_NOTATTACHED) {
|
||||
dev->attached = 0;
|
||||
} else {
|
||||
dev->attached = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_usb_device = {
|
||||
.name = "USBDevice",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = usb_device_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT8(addr, USBDevice),
|
||||
VMSTATE_INT32(state, USBDevice),
|
||||
|
@ -414,16 +414,17 @@ struct EHCIState {
|
||||
*/
|
||||
QEMUTimer *frame_timer;
|
||||
QEMUBH *async_bh;
|
||||
int astate; // Current state in asynchronous schedule
|
||||
int pstate; // Current state in periodic schedule
|
||||
uint32_t astate; /* Current state in asynchronous schedule */
|
||||
uint32_t pstate; /* Current state in periodic schedule */
|
||||
USBPort ports[NB_PORTS];
|
||||
USBPort *companion_ports[NB_PORTS];
|
||||
uint32_t usbsts_pending;
|
||||
EHCIQueueHead aqueues;
|
||||
EHCIQueueHead pqueues;
|
||||
|
||||
uint32_t a_fetch_addr; // which address to look at next
|
||||
uint32_t p_fetch_addr; // which address to look at next
|
||||
/* which address to look at next */
|
||||
uint32_t a_fetch_addr;
|
||||
uint32_t p_fetch_addr;
|
||||
|
||||
USBPacket ipacket;
|
||||
QEMUSGList isgl;
|
||||
@ -568,6 +569,7 @@ static inline void ehci_set_interrupt(EHCIState *s, int intr)
|
||||
level = 1;
|
||||
}
|
||||
|
||||
trace_usb_ehci_interrupt(level, s->usbsts, s->usbintr);
|
||||
qemu_set_irq(s->irq, level);
|
||||
}
|
||||
|
||||
@ -821,8 +823,9 @@ static void ehci_attach(USBPort *port)
|
||||
{
|
||||
EHCIState *s = port->opaque;
|
||||
uint32_t *portsc = &s->portsc[port->index];
|
||||
const char *owner = (*portsc & PORTSC_POWNER) ? "comp" : "ehci";
|
||||
|
||||
trace_usb_ehci_port_attach(port->index, port->dev->product_desc);
|
||||
trace_usb_ehci_port_attach(port->index, owner, port->dev->product_desc);
|
||||
|
||||
if (*portsc & PORTSC_POWNER) {
|
||||
USBPort *companion = s->companion_ports[port->index];
|
||||
@ -841,8 +844,9 @@ static void ehci_detach(USBPort *port)
|
||||
{
|
||||
EHCIState *s = port->opaque;
|
||||
uint32_t *portsc = &s->portsc[port->index];
|
||||
const char *owner = (*portsc & PORTSC_POWNER) ? "comp" : "ehci";
|
||||
|
||||
trace_usb_ehci_port_detach(port->index);
|
||||
trace_usb_ehci_port_detach(port->index, owner);
|
||||
|
||||
if (*portsc & PORTSC_POWNER) {
|
||||
USBPort *companion = s->companion_ports[port->index];
|
||||
@ -2390,9 +2394,58 @@ static USBBusOps ehci_bus_ops = {
|
||||
.register_companion = ehci_register_companion,
|
||||
};
|
||||
|
||||
static int usb_ehci_post_load(void *opaque, int version_id)
|
||||
{
|
||||
EHCIState *s = opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NB_PORTS; i++) {
|
||||
USBPort *companion = s->companion_ports[i];
|
||||
if (companion == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (s->portsc[i] & PORTSC_POWNER) {
|
||||
companion->dev = s->ports[i].dev;
|
||||
} else {
|
||||
companion->dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ehci = {
|
||||
.name = "ehci",
|
||||
.unmigratable = 1,
|
||||
.name = "ehci",
|
||||
.version_id = 1,
|
||||
.post_load = usb_ehci_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(dev, EHCIState),
|
||||
/* mmio registers */
|
||||
VMSTATE_UINT32(usbcmd, EHCIState),
|
||||
VMSTATE_UINT32(usbsts, EHCIState),
|
||||
VMSTATE_UINT32(usbintr, EHCIState),
|
||||
VMSTATE_UINT32(frindex, EHCIState),
|
||||
VMSTATE_UINT32(ctrldssegment, EHCIState),
|
||||
VMSTATE_UINT32(periodiclistbase, EHCIState),
|
||||
VMSTATE_UINT32(asynclistaddr, EHCIState),
|
||||
VMSTATE_UINT32(configflag, EHCIState),
|
||||
VMSTATE_UINT32(portsc[0], EHCIState),
|
||||
VMSTATE_UINT32(portsc[1], EHCIState),
|
||||
VMSTATE_UINT32(portsc[2], EHCIState),
|
||||
VMSTATE_UINT32(portsc[3], EHCIState),
|
||||
VMSTATE_UINT32(portsc[4], EHCIState),
|
||||
VMSTATE_UINT32(portsc[5], EHCIState),
|
||||
/* frame timer */
|
||||
VMSTATE_TIMER(frame_timer, EHCIState),
|
||||
VMSTATE_UINT64(last_run_ns, EHCIState),
|
||||
VMSTATE_UINT32(async_stepdown, EHCIState),
|
||||
/* schedule state */
|
||||
VMSTATE_UINT32(astate, EHCIState),
|
||||
VMSTATE_UINT32(pstate, EHCIState),
|
||||
VMSTATE_UINT32(a_fetch_addr, EHCIState),
|
||||
VMSTATE_UINT32(p_fetch_addr, EHCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property ehci_properties[] = {
|
||||
|
@ -292,10 +292,10 @@ static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
|
||||
|
||||
static void uhci_async_cancel_all(UHCIState *s)
|
||||
{
|
||||
UHCIQueue *queue;
|
||||
UHCIQueue *queue, *nq;
|
||||
UHCIAsync *curr, *n;
|
||||
|
||||
QTAILQ_FOREACH(queue, &s->queues, next) {
|
||||
QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) {
|
||||
QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) {
|
||||
uhci_async_unlink(curr);
|
||||
uhci_async_cancel(curr);
|
||||
|
@ -111,6 +111,7 @@ typedef struct USBHostDevice {
|
||||
uint32_t iso_urb_count;
|
||||
uint32_t options;
|
||||
Notifier exit;
|
||||
QEMUBH *bh;
|
||||
|
||||
struct endp_data ep_in[USB_MAX_ENDPOINTS];
|
||||
struct endp_data ep_out[USB_MAX_ENDPOINTS];
|
||||
@ -1421,6 +1422,43 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is *NOT* about restoring state. We have absolutely no idea
|
||||
* what state the host device is in at the moment and whenever it is
|
||||
* still present in the first place. Attemping to contine where we
|
||||
* left off is impossible.
|
||||
*
|
||||
* What we are going to to to here is emulate a surprise removal of
|
||||
* the usb device passed through, then kick host scan so the device
|
||||
* will get re-attached (and re-initialized by the guest) in case it
|
||||
* is still present.
|
||||
*
|
||||
* As the device removal will change the state of other devices (usb
|
||||
* host controller, most likely interrupt controller too) we have to
|
||||
* wait with it until *all* vmstate is loaded. Thus post_load just
|
||||
* kicks a bottom half which then does the actual work.
|
||||
*/
|
||||
static void usb_host_post_load_bh(void *opaque)
|
||||
{
|
||||
USBHostDevice *dev = opaque;
|
||||
|
||||
if (dev->fd != -1) {
|
||||
usb_host_close(dev);
|
||||
}
|
||||
if (dev->dev.attached) {
|
||||
usb_device_detach(&dev->dev);
|
||||
}
|
||||
usb_host_auto_check(NULL);
|
||||
}
|
||||
|
||||
static int usb_host_post_load(void *opaque, int version_id)
|
||||
{
|
||||
USBHostDevice *dev = opaque;
|
||||
|
||||
qemu_bh_schedule(dev->bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_host_initfn(USBDevice *dev)
|
||||
{
|
||||
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
|
||||
@ -1432,6 +1470,7 @@ static int usb_host_initfn(USBDevice *dev)
|
||||
QTAILQ_INSERT_TAIL(&hostdevs, s, next);
|
||||
s->exit.notify = usb_host_exit_notifier;
|
||||
qemu_add_exit_notifier(&s->exit);
|
||||
s->bh = qemu_bh_new(usb_host_post_load_bh, s);
|
||||
usb_host_auto_check(NULL);
|
||||
|
||||
if (s->match.bus_num != 0 && s->match.port != NULL) {
|
||||
@ -1443,7 +1482,13 @@ static int usb_host_initfn(USBDevice *dev)
|
||||
|
||||
static const VMStateDescription vmstate_usb_host = {
|
||||
.name = "usb-host",
|
||||
.unmigratable = 1,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = usb_host_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_USB_DEVICE(dev, USBHostDevice),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property usb_host_dev_properties[] = {
|
||||
@ -1737,25 +1782,27 @@ static void usb_host_auto_check(void *unused)
|
||||
struct USBHostDevice *s;
|
||||
int unconnected = 0;
|
||||
|
||||
usb_host_scan(NULL, usb_host_auto_scan);
|
||||
if (runstate_is_running()) {
|
||||
usb_host_scan(NULL, usb_host_auto_scan);
|
||||
|
||||
QTAILQ_FOREACH(s, &hostdevs, next) {
|
||||
if (s->fd == -1) {
|
||||
unconnected++;
|
||||
QTAILQ_FOREACH(s, &hostdevs, next) {
|
||||
if (s->fd == -1) {
|
||||
unconnected++;
|
||||
}
|
||||
if (s->seen == 0) {
|
||||
s->errcount = 0;
|
||||
}
|
||||
s->seen = 0;
|
||||
}
|
||||
if (s->seen == 0) {
|
||||
s->errcount = 0;
|
||||
}
|
||||
s->seen = 0;
|
||||
}
|
||||
|
||||
if (unconnected == 0) {
|
||||
/* nothing to watch */
|
||||
if (usb_auto_timer) {
|
||||
qemu_del_timer(usb_auto_timer);
|
||||
trace_usb_host_auto_scan_disabled();
|
||||
if (unconnected == 0) {
|
||||
/* nothing to watch */
|
||||
if (usb_auto_timer) {
|
||||
qemu_del_timer(usb_auto_timer);
|
||||
trace_usb_host_auto_scan_disabled();
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!usb_auto_timer) {
|
||||
|
@ -252,12 +252,13 @@ usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QT
|
||||
usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
|
||||
usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
|
||||
usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ %08x: next %08x - active %d"
|
||||
usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
|
||||
usb_ehci_port_detach(uint32_t port) "detach port #%d"
|
||||
usb_ehci_port_attach(uint32_t port, const char *owner, const char *device) "attach port #%d, owner %s, device %s"
|
||||
usb_ehci_port_detach(uint32_t port, const char *owner) "detach port #%d, owner %s"
|
||||
usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
|
||||
usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
|
||||
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_interrupt(uint32_t level, uint32_t sts, uint32_t mask) "level %d, sts 0x%x, mask 0x%x"
|
||||
|
||||
# hw/usb/hcd-uhci.c
|
||||
usb_uhci_reset(void) "=== RESET ==="
|
||||
|
Loading…
x
Reference in New Issue
Block a user