summaryrefslogtreecommitdiff
path: root/hw/usb/hcd-ehci-pci.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-11-15 13:07:49 +0100
committerGerd Hoffmann <kraxel@redhat.com>2012-11-16 11:27:32 +0100
commit55903f1d2d8abfa8d7610ab32a4046a1ed4fdbb8 (patch)
treec82911f7129a40b4756e9e5f300d471e588b72e3 /hw/usb/hcd-ehci-pci.c
parent40862309a9d733cb0e878c79f477de003897b5d2 (diff)
downloadqemu-55903f1d2d8abfa8d7610ab32a4046a1ed4fdbb8.tar.gz
ehci: handle dma errors
Starting with commit 1c380f9460522f32c8dd2577b2a53d518ec91c6d dma transfers can actually fail. This patch makes ehci keep track of the busmaster bit in pci config space, by setting/clearing the dma_context pointer. Attempts to dma without context will result in raising HSE (Host System Error) interrupt and stopping the host controller. This patch fixes WinXP not booting with a usb stick attached to ehci. Root cause is seabios activating ehci so you can boot from the stick, and WinXP clearing the busmaster bit before resetting the host controller, leading to ehci actually trying dma while it is disabled. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb/hcd-ehci-pci.c')
-rw-r--r--hw/usb/hcd-ehci-pci.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index fe45a1fbba..5887eab197 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -17,6 +17,7 @@
#include "hw/usb/hcd-ehci.h"
#include "hw/pci.h"
+#include "range.h"
typedef struct EHCIPCIState {
PCIDevice pcidev;
@@ -79,6 +80,21 @@ static int usb_ehci_pci_initfn(PCIDevice *dev)
return 0;
}
+static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
+ uint32_t val, int l)
+{
+ EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
+ bool busmaster;
+
+ pci_default_write_config(dev, addr, val, l);
+
+ if (!range_covers_byte(addr, l, PCI_COMMAND)) {
+ return;
+ }
+ busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER;
+ i->ehci.dma = busmaster ? pci_dma_context(dev) : NULL;
+}
+
static Property ehci_pci_properties[] = {
DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
DEFINE_PROP_END_OF_LIST(),
@@ -106,6 +122,7 @@ static void ehci_class_init(ObjectClass *klass, void *data)
k->device_id = i->device_id;
k->revision = i->revision;
k->class_id = PCI_CLASS_SERIAL_USB;
+ k->config_write = usb_ehci_pci_write_config;
dc->vmsd = &vmstate_ehci_pci;
dc->props = ehci_pci_properties;
}