When the USB OHCI controller starts, a periodic end-of-frame routine writes to a chunk of memory set aside by the device driver. If the machine reboots or the OS kexecs, the controller continues writing even though the memory is no longer owned by the device driver, causing random, mysterious corruption, until the new OS reinitializes the OHCI controller.
The attached patch fixes this by resetting the controller whenever the machine reboots or the device driver issues a reset command, and disabling the timer when the controller resets. --Ed
Index: qemu-snapshot-2007-02-09_05/hw/usb-ohci.c =================================================================== --- qemu-snapshot-2007-02-09_05.orig/hw/usb-ohci.c +++ qemu-snapshot-2007-02-09_05/hw/usb-ohci.c @@ -106,6 +106,8 @@ struct ohci_hcca { uint32_t done; }; +static void ohci_bus_stop(OHCIState *ohci); + /* Bitfields for the first word of an Endpoint Desciptor. */ #define OHCI_ED_FA_SHIFT 0 #define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT) @@ -323,11 +325,13 @@ static void ohci_attach(USBPort *port1, } /* Reset the controller */ -static void ohci_reset(OHCIState *ohci) +static void ohci_reset(void *opaque) { + OHCIState *ohci = opaque; OHCIPort *port; int i; + ohci_bus_stop(ohci); ohci->ctl = 0; ohci->old_ctl = 0; ohci->status = 0; @@ -813,6 +817,7 @@ static void ohci_bus_stop(OHCIState *ohc { if (ohci->eof_timer) qemu_del_timer(ohci->eof_timer); + ohci->eof_timer = NULL; } /* Sets a flag in a port status register but only set it if the port is @@ -898,6 +903,7 @@ static void ohci_set_ctl(OHCIState *ohci dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name); break; case OHCI_USB_RESET: + ohci_reset(ohci); dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name); break; } @@ -1266,5 +1272,6 @@ void usb_ohci_init(struct PCIBus *bus, i } ohci->async_td = 0; + qemu_register_reset(ohci_reset, ohci); ohci_reset(ohci); }