Skip to content

Commit

Permalink
Merge remote-tracking branch 'kraxel/usb.71' into staging
Browse files Browse the repository at this point in the history
* kraxel/usb.71:
  usb-host: fix splitted transfers
  usb-host: update tracing
  usb-redir: Set default debug level to warning
  usb-redir: Only add actually in flight packets to the in flight queue
  ehci: handle dma errors
  ehci: keep the frame timer running in case the guest asked for frame list rollover interrupts
  ehci: Don't verify the next pointer for periodic qh-s and qtd-s
  ehci: Better detection for qtd-s linked in circles
  ehci: Fixup q->qtdaddr after cancelling an already completed packet
  ehci: Don't access packet after freeing it
  usb: host-linux: Ignore parsing errors of the device descriptors
  usb-host: scan for usb devices when the vm starts
  usb: Fix (another) bug in usb_packet_map() for IOMMU handling
  fix live migration

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
  • Loading branch information
Anthony Liguori committed Nov 19, 2012
2 parents c562d15 + 71e0aa3 commit 5cc82c2
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 63 deletions.
4 changes: 4 additions & 0 deletions hw/pci.c
Expand Up @@ -367,6 +367,10 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)

pci_update_mappings(s);

memory_region_set_enabled(&s->bus_master_enable_region,
pci_get_word(s->config + PCI_COMMAND)
& PCI_COMMAND_MASTER);

g_free(config);
return 0;
}
Expand Down
17 changes: 17 additions & 0 deletions hw/usb/hcd-ehci-pci.c
Expand Up @@ -17,6 +17,7 @@

#include "hw/usb/hcd-ehci.h"
#include "hw/pci.h"
#include "range.h"

typedef struct EHCIPCIState {
PCIDevice pcidev;
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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;
}
Expand Down
101 changes: 72 additions & 29 deletions hw/usb/hcd-ehci.c
Expand Up @@ -189,6 +189,7 @@ static const char *ehci_mmio_names[] = {

static int ehci_state_executing(EHCIQueue *q);
static int ehci_state_writeback(EHCIQueue *q);
static int ehci_state_advqueue(EHCIQueue *q);
static int ehci_fill_queue(EHCIPacket *p);

static const char *nr2str(const char **n, size_t len, uint32_t nr)
Expand Down Expand Up @@ -453,12 +454,16 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
static void ehci_free_packet(EHCIPacket *p)
{
if (p->async == EHCI_ASYNC_FINISHED) {
int state = ehci_get_state(p->queue->ehci, p->queue->async);
EHCIQueue *q = p->queue;
int state = ehci_get_state(q->ehci, q->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);
ehci_state_executing(q);
ehci_state_writeback(q);
if (!(q->qh.token & QTD_TOKEN_HALT)) {
ehci_state_advqueue(q);
}
ehci_set_state(q->ehci, q->async, state);
/* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */
return;
}
Expand Down Expand Up @@ -959,6 +964,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,

case USBINTR:
val &= USBINTR_MASK;
if (ehci_enabled(s) && (USBSTS_FLR & val)) {
qemu_bh_schedule(s->async_bh);
}
break;

case FRINDEX:
Expand Down Expand Up @@ -995,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 */
Expand All @@ -1018,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;
}

/*
Expand Down Expand Up @@ -1435,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) {
Expand Down Expand Up @@ -1533,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);

/*
Expand All @@ -1545,8 +1569,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
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) ||
(qh.current_qtd != q->qh.current_qtd) ||
(q->async && qh.next_qtd != q->qh.next_qtd) ||
(memcmp(&qh.altnext_qtd, &q->qh.altnext_qtd,
7 * sizeof(uint32_t)) != 0) ||
(q->dev != NULL && q->dev->addr != devaddr)) {
if (ehci_reset_queue(q) > 0) {
ehci_trace_guest_bug(ehci, "guest updated active QH");
Expand Down Expand Up @@ -1621,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) {
Expand All @@ -1645,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)) {
Expand Down Expand Up @@ -1707,14 +1737,17 @@ 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);
if (p != NULL) {
if (p->qtdaddr != q->qtdaddr ||
(!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) ||
(q->async && !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]) {
ehci_cancel_queue(q);
Expand Down Expand Up @@ -1785,7 +1818,7 @@ static int ehci_fill_queue(EHCIPacket *p)
USBEndpoint *ep = p->packet.ep;
EHCIQueue *q = p->queue;
EHCIqtd qtd = p->qtd;
uint32_t qtdaddr, start_addr = p->qtdaddr;
uint32_t qtdaddr;

for (;;) {
if (NLPTR_TBIT(qtd.next) != 0) {
Expand All @@ -1796,11 +1829,15 @@ static int ehci_fill_queue(EHCIPacket *p)
* Detect circular td lists, Windows creates these, counting on the
* active bit going low after execution to make the queue stop.
*/
if (qtdaddr == start_addr) {
break;
QTAILQ_FOREACH(p, &q->packets, next) {
if (p->qtdaddr == qtdaddr) {
goto leave;
}
}
if (get_dwords(q->ehci, NLPTR_GET(qtdaddr),
(uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) {
return -1;
}
get_dwords(q->ehci, NLPTR_GET(qtdaddr),
(uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd);
if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
break;
Expand All @@ -1814,6 +1851,7 @@ static int ehci_fill_queue(EHCIPacket *p)
assert(p->packet.status == USB_RET_ASYNC);
p->async = EHCI_ASYNC_INFLIGHT;
}
leave:
usb_device_flush_ep_queue(ep->dev, ep);
return 1;
}
Expand Down Expand Up @@ -2098,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);
Expand Down Expand Up @@ -2209,6 +2248,10 @@ static void ehci_frame_timer(void *opaque)
ehci->async_stepdown = 0;
}

if (ehci_enabled(ehci) && (ehci->usbintr & USBSTS_FLR)) {
need_timer++;
}

if (need_timer) {
/* If we've raised int, we speed up the timer, so that we quickly
* notice any new packets queued up in response */
Expand Down

0 comments on commit 5cc82c2

Please sign in to comment.