aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb/hcd-ehci-pci.c17
-rw-r--r--hw/usb/hcd-ehci.c63
-rw-r--r--trace-events1
3 files changed, 62 insertions, 19 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;
}
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 14269dafed..7df8e21ecb 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1003,21 +1003,25 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
*mmio, old);
}
-
-// TODO : Put in common header file, duplication from usb-ohci.c
-
/* Get an array of dwords from main memory */
static inline int get_dwords(EHCIState *ehci, uint32_t addr,
uint32_t *buf, int num)
{
int i;
+ if (!ehci->dma) {
+ ehci_raise_irq(ehci, USBSTS_HSE);
+ ehci->usbcmd &= ~USBCMD_RUNSTOP;
+ trace_usb_ehci_dma_error();
+ return -1;
+ }
+
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
dma_memory_read(ehci->dma, addr, buf, sizeof(*buf));
*buf = le32_to_cpu(*buf);
}
- return 1;
+ return num;
}
/* Put an array of dwords in to main memory */
@@ -1026,12 +1030,19 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr,
{
int i;
+ if (!ehci->dma) {
+ ehci_raise_irq(ehci, USBSTS_HSE);
+ ehci->usbcmd &= ~USBCMD_RUNSTOP;
+ trace_usb_ehci_dma_error();
+ return -1;
+ }
+
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp));
}
- return 1;
+ return num;
}
/*
@@ -1443,8 +1454,10 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
/* Find the head of the list (4.9.1.1) */
for(i = 0; i < MAX_QH; i++) {
- get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
- sizeof(EHCIqh) >> 2);
+ if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
+ sizeof(EHCIqh) >> 2) < 0) {
+ return 0;
+ }
ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
if (qh.epchar & QH_EPCHAR_H) {
@@ -1541,8 +1554,11 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
goto out;
}
- get_dwords(ehci, NLPTR_GET(q->qhaddr),
- (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
+ if (get_dwords(ehci, NLPTR_GET(q->qhaddr),
+ (uint32_t *) &qh, sizeof(EHCIqh) >> 2) < 0) {
+ q = NULL;
+ goto out;
+ }
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh);
/*
@@ -1631,8 +1647,10 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
assert(!async);
entry = ehci_get_fetch_addr(ehci, async);
- get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
- sizeof(EHCIitd) >> 2);
+ if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
+ sizeof(EHCIitd) >> 2) < 0) {
+ return -1;
+ }
ehci_trace_itd(ehci, entry, &itd);
if (ehci_process_itd(ehci, &itd, entry) != 0) {
@@ -1655,8 +1673,10 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
assert(!async);
entry = ehci_get_fetch_addr(ehci, async);
- get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd,
- sizeof(EHCIsitd) >> 2);
+ if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd,
+ sizeof(EHCIsitd) >> 2) < 0) {
+ return 0;
+ }
ehci_trace_sitd(ehci, entry, &sitd);
if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
@@ -1717,8 +1737,10 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
EHCIPacket *p;
int again = 1;
- get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
- sizeof(EHCIqtd) >> 2);
+ if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
+ sizeof(EHCIqtd) >> 2) < 0) {
+ return 0;
+ }
ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
p = QTAILQ_FIRST(&q->packets);
@@ -1812,8 +1834,10 @@ static int ehci_fill_queue(EHCIPacket *p)
goto leave;
}
}
- get_dwords(q->ehci, NLPTR_GET(qtdaddr),
- (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
+ if (get_dwords(q->ehci, NLPTR_GET(qtdaddr),
+ (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) {
+ return -1;
+ }
ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd);
if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
break;
@@ -2112,8 +2136,9 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
}
list |= ((ehci->frindex & 0x1ff8) >> 1);
- dma_memory_read(ehci->dma, list, &entry, sizeof entry);
- entry = le32_to_cpu(entry);
+ if (get_dwords(ehci, list, &entry, 1) < 0) {
+ break;
+ }
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
ehci->frindex / 8, list, entry);
diff --git a/trace-events b/trace-events
index e1a37cc26f..35308be525 100644
--- a/trace-events
+++ b/trace-events
@@ -286,6 +286,7 @@ usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "lev
usb_ehci_guest_bug(const char *reason) "%s"
usb_ehci_doorbell_ring(void) ""
usb_ehci_doorbell_ack(void) ""
+usb_ehci_dma_error(void) ""
# hw/usb/hcd-uhci.c
usb_uhci_reset(void) "=== RESET ==="