Merge remote-tracking branch 'kraxel/usb.66' into staging

* kraxel/usb.66:
  usb: Fix usb_packet_map() in the presence of IOMMUs
  usb-redir: Adjust pkg-config check for usbredirparser .pc file rename (v2)
  ehci: Fix interrupt packet MULT handling
  xhci: create a memory region for each port
  xhci: route string & usb hub support
  xhci: tweak limits
  compat: turn off msi/msix on xhci for old machine types
  add pc-1.3 machine type

Conflicts:
	hw/pc_piix.c

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2012-10-04 19:49:15 -05:00
commit 938406dfb1
4 changed files with 140 additions and 109 deletions

6
configure vendored
View file

@ -2748,10 +2748,10 @@ fi
# check for usbredirparser for usb network redirection support # check for usbredirparser for usb network redirection support
if test "$usb_redir" != "no" ; then if test "$usb_redir" != "no" ; then
if $pkg_config --atleast-version=0.5 libusbredirparser >/dev/null 2>&1 ; then if $pkg_config --atleast-version=0.5 libusbredirparser-0.5 >/dev/null 2>&1 ; then
usb_redir="yes" usb_redir="yes"
usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null)
usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null)
QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags" QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
libs_softmmu="$libs_softmmu $usb_redir_libs" libs_softmmu="$libs_softmmu $usb_redir_libs"
else else

View file

@ -373,6 +373,7 @@ struct EHCIQueue {
uint32_t seen; uint32_t seen;
uint64_t ts; uint64_t ts;
int async; int async;
int transact_ctr;
/* cached data from guest - needs to be flushed /* cached data from guest - needs to be flushed
* when guest removes an entry (doorbell, handshake sequence) * when guest removes an entry (doorbell, handshake sequence)
@ -1837,6 +1838,11 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
} }
q->qh = qh; q->qh = qh;
q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT);
if (q->transact_ctr == 0) { /* Guest bug in some versions of windows */
q->transact_ctr = 4;
}
if (q->dev == NULL) { if (q->dev == NULL) {
q->dev = ehci_find_device(q->ehci, devaddr); q->dev = ehci_find_device(q->ehci, devaddr);
} }
@ -2014,11 +2020,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
} else if (p != NULL) { } else if (p != NULL) {
switch (p->async) { switch (p->async) {
case EHCI_ASYNC_NONE: case EHCI_ASYNC_NONE:
/* Should never happen packet should at least be initialized */
assert(0);
break;
case EHCI_ASYNC_INITIALIZED: case EHCI_ASYNC_INITIALIZED:
/* Previously nacked packet (likely interrupt ep) */ /* Not yet executed (MULT), or previously nacked (int) packet */
ehci_set_state(q->ehci, q->async, EST_EXECUTE); ehci_set_state(q->ehci, q->async, EST_EXECUTE);
break; break;
case EHCI_ASYNC_INFLIGHT: case EHCI_ASYNC_INFLIGHT:
@ -2107,15 +2110,12 @@ static int ehci_state_execute(EHCIQueue *q)
// TODO verify enough time remains in the uframe as in 4.4.1.1 // TODO verify enough time remains in the uframe as in 4.4.1.1
// TODO write back ptr to async list when done or out of time // TODO write back ptr to async list when done or out of time
// TODO Windows does not seem to ever set the MULT field
if (!q->async) { /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); if (!q->async && q->transact_ctr == 0) {
if (!transactCtr) { ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1;
again = 1; goto out;
goto out;
}
} }
if (q->async) { if (q->async) {
@ -2132,7 +2132,11 @@ static int ehci_state_execute(EHCIQueue *q)
trace_usb_ehci_packet_action(p->queue, p, "async"); trace_usb_ehci_packet_action(p->queue, p, "async");
p->async = EHCI_ASYNC_INFLIGHT; p->async = EHCI_ASYNC_INFLIGHT;
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; if (q->async) {
again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
} else {
again = 1;
}
goto out; goto out;
} }
@ -2152,13 +2156,9 @@ static int ehci_state_executing(EHCIQueue *q)
ehci_execute_complete(q); ehci_execute_complete(q);
// 4.10.3 /* 4.10.3 */
if (!q->async) { if (!q->async && q->transact_ctr > 0) {
int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); q->transact_ctr--;
transactCtr--;
set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT);
// 4.10.3, bottom of page 82, should exit this state when transaction
// counter decrements to 0
} }
/* 4.10.5 */ /* 4.10.5 */

View file

@ -37,12 +37,12 @@
#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ #define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
__func__, __LINE__); abort(); } while (0) __func__, __LINE__); abort(); } while (0)
#define MAXPORTS_2 8 #define MAXPORTS_2 15
#define MAXPORTS_3 8 #define MAXPORTS_3 15
#define MAXPORTS (MAXPORTS_2+MAXPORTS_3) #define MAXPORTS (MAXPORTS_2+MAXPORTS_3)
#define MAXSLOTS MAXPORTS #define MAXSLOTS 64
#define MAXINTRS MAXPORTS #define MAXINTRS 16
#define TD_QUEUE 24 #define TD_QUEUE 24
@ -285,6 +285,8 @@ typedef enum TRBCCode {
#define SLOT_CONTEXT_ENTRIES_MASK 0x1f #define SLOT_CONTEXT_ENTRIES_MASK 0x1f
#define SLOT_CONTEXT_ENTRIES_SHIFT 27 #define SLOT_CONTEXT_ENTRIES_SHIFT 27
typedef struct XHCIState XHCIState;
typedef enum EPType { typedef enum EPType {
ET_INVALID = 0, ET_INVALID = 0,
ET_ISO_OUT, ET_ISO_OUT,
@ -303,15 +305,15 @@ typedef struct XHCIRing {
} XHCIRing; } XHCIRing;
typedef struct XHCIPort { typedef struct XHCIPort {
XHCIState *xhci;
uint32_t portsc; uint32_t portsc;
uint32_t portnr; uint32_t portnr;
USBPort *uport; USBPort *uport;
uint32_t speedmask; uint32_t speedmask;
char name[16];
MemoryRegion mem;
} XHCIPort; } XHCIPort;
struct XHCIState;
typedef struct XHCIState XHCIState;
typedef struct XHCITransfer { typedef struct XHCITransfer {
XHCIState *xhci; XHCIState *xhci;
USBPacket packet; USBPacket packet;
@ -363,7 +365,7 @@ typedef struct XHCIEPContext {
typedef struct XHCISlot { typedef struct XHCISlot {
bool enabled; bool enabled;
dma_addr_t ctx; dma_addr_t ctx;
unsigned int port; USBPort *uport;
unsigned int devaddr; unsigned int devaddr;
XHCIEPContext * eps[31]; XHCIEPContext * eps[31];
} XHCISlot; } XHCISlot;
@ -1230,7 +1232,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
ep |= 0x80; ep |= 0x80;
} }
dev = xhci->ports[xhci->slots[slotid-1].port-1].uport->dev; dev = xhci->slots[slotid-1].uport->dev;
if (!dev) { if (!dev) {
return CC_USB_TRANSACTION_ERROR; return CC_USB_TRANSACTION_ERROR;
} }
@ -1412,18 +1414,9 @@ static void xhci_stall_ep(XHCITransfer *xfer)
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
XHCIEPContext *epctx); XHCIEPContext *epctx);
static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr)
{
if (!(port->portsc & PORTSC_PED)) {
return NULL;
}
return usb_find_device(port->uport, addr);
}
static int xhci_setup_packet(XHCITransfer *xfer) static int xhci_setup_packet(XHCITransfer *xfer)
{ {
XHCIState *xhci = xfer->xhci; XHCIState *xhci = xfer->xhci;
XHCIPort *port;
USBDevice *dev; USBDevice *dev;
USBEndpoint *ep; USBEndpoint *ep;
int dir; int dir;
@ -1434,13 +1427,12 @@ static int xhci_setup_packet(XHCITransfer *xfer)
ep = xfer->packet.ep; ep = xfer->packet.ep;
dev = ep->dev; dev = ep->dev;
} else { } else {
port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; if (!xhci->slots[xfer->slotid-1].uport) {
dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); fprintf(stderr, "xhci: slot %d has no device\n",
if (!dev) { xfer->slotid);
fprintf(stderr, "xhci: slot %d port %d has no device\n",
xfer->slotid, xhci->slots[xfer->slotid-1].port);
return -1; return -1;
} }
dev = xhci->slots[xfer->slotid-1].uport->dev;
ep = usb_ep_get(dev, dir, xfer->epid >> 1); ep = usb_ep_get(dev, dir, xfer->epid >> 1);
} }
@ -1772,7 +1764,7 @@ static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
trace_usb_xhci_slot_enable(slotid); trace_usb_xhci_slot_enable(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
xhci->slots[slotid-1].enabled = 1; xhci->slots[slotid-1].enabled = 1;
xhci->slots[slotid-1].port = 0; xhci->slots[slotid-1].uport = NULL;
memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31); memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31);
return CC_SUCCESS; return CC_SUCCESS;
@ -1795,17 +1787,42 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
return CC_SUCCESS; return CC_SUCCESS;
} }
static USBPort *xhci_lookup_uport(XHCIState *xhci, uint32_t *slot_ctx)
{
USBPort *uport;
char path[32];
int i, pos, port;
port = (slot_ctx[1]>>16) & 0xFF;
port = xhci->ports[port-1].uport->index+1;
pos = snprintf(path, sizeof(path), "%d", port);
for (i = 0; i < 5; i++) {
port = (slot_ctx[0] >> 4*i) & 0x0f;
if (!port) {
break;
}
pos += snprintf(path + pos, sizeof(path) - pos, ".%d", port);
}
QTAILQ_FOREACH(uport, &xhci->bus.used, next) {
if (strcmp(uport->path, path) == 0) {
return uport;
}
}
return NULL;
}
static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
uint64_t pictx, bool bsr) uint64_t pictx, bool bsr)
{ {
XHCISlot *slot; XHCISlot *slot;
USBPort *uport;
USBDevice *dev; USBDevice *dev;
dma_addr_t ictx, octx, dcbaap; dma_addr_t ictx, octx, dcbaap;
uint64_t poctx; uint64_t poctx;
uint32_t ictl_ctx[2]; uint32_t ictl_ctx[2];
uint32_t slot_ctx[4]; uint32_t slot_ctx[4];
uint32_t ep0_ctx[5]; uint32_t ep0_ctx[5];
unsigned int port;
int i; int i;
TRBCCode res; TRBCCode res;
@ -1837,27 +1854,28 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n", DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
port = (slot_ctx[1]>>16) & 0xFF; uport = xhci_lookup_uport(xhci, slot_ctx);
dev = xhci->ports[port-1].uport->dev; if (uport == NULL) {
fprintf(stderr, "xhci: port not found\n");
if (port < 1 || port > xhci->numports) {
fprintf(stderr, "xhci: bad port %d\n", port);
return CC_TRB_ERROR; return CC_TRB_ERROR;
} else if (!dev) { }
fprintf(stderr, "xhci: port %d not connected\n", port);
dev = uport->dev;
if (!dev) {
fprintf(stderr, "xhci: port %s not connected\n", uport->path);
return CC_USB_TRANSACTION_ERROR; return CC_USB_TRANSACTION_ERROR;
} }
for (i = 0; i < MAXSLOTS; i++) { for (i = 0; i < MAXSLOTS; i++) {
if (xhci->slots[i].port == port) { if (xhci->slots[i].uport == uport) {
fprintf(stderr, "xhci: port %d already assigned to slot %d\n", fprintf(stderr, "xhci: port %s already assigned to slot %d\n",
port, i+1); uport->path, i+1);
return CC_TRB_ERROR; return CC_TRB_ERROR;
} }
} }
slot = &xhci->slots[slotid-1]; slot = &xhci->slots[slotid-1];
slot->port = port; slot->uport = uport;
slot->ctx = octx; slot->ctx = octx;
if (bsr) { if (bsr) {
@ -2414,20 +2432,14 @@ static uint64_t xhci_cap_read(void *ptr, target_phys_addr_t reg, unsigned size)
return ret; return ret;
} }
static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) static uint64_t xhci_port_read(void *ptr, target_phys_addr_t reg, unsigned size)
{ {
uint32_t port = reg >> 4; XHCIPort *port = ptr;
uint32_t ret; uint32_t ret;
if (port >= xhci->numports) { switch (reg) {
fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
ret = 0;
goto out;
}
switch (reg & 0xf) {
case 0x00: /* PORTSC */ case 0x00: /* PORTSC */
ret = xhci->ports[port].portsc; ret = port->portsc;
break; break;
case 0x04: /* PORTPMSC */ case 0x04: /* PORTPMSC */
case 0x08: /* PORTLI */ case 0x08: /* PORTLI */
@ -2436,30 +2448,25 @@ static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg)
case 0x0c: /* reserved */ case 0x0c: /* reserved */
default: default:
fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n", fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
port, reg); port->portnr, (uint32_t)reg);
ret = 0; ret = 0;
} }
out: trace_usb_xhci_port_read(port->portnr, reg, ret);
trace_usb_xhci_port_read(port, reg & 0x0f, ret);
return ret; return ret;
} }
static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) static void xhci_port_write(void *ptr, target_phys_addr_t reg,
uint64_t val, unsigned size)
{ {
uint32_t port = reg >> 4; XHCIPort *port = ptr;
uint32_t portsc; uint32_t portsc;
trace_usb_xhci_port_write(port, reg & 0x0f, val); trace_usb_xhci_port_write(port->portnr, reg, val);
if (port >= xhci->numports) { switch (reg) {
fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
return;
}
switch (reg & 0xf) {
case 0x00: /* PORTSC */ case 0x00: /* PORTSC */
portsc = xhci->ports[port].portsc; portsc = port->portsc;
/* write-1-to-clear bits*/ /* write-1-to-clear bits*/
portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC| portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC|
PORTSC_PRC|PORTSC_PLC|PORTSC_CEC)); PORTSC_PRC|PORTSC_PLC|PORTSC_CEC));
@ -2474,16 +2481,16 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
/* write-1-to-start bits */ /* write-1-to-start bits */
if (val & PORTSC_PR) { if (val & PORTSC_PR) {
DPRINTF("xhci: port %d reset\n", port); DPRINTF("xhci: port %d reset\n", port);
usb_device_reset(xhci->ports[port].uport->dev); usb_device_reset(port->uport->dev);
portsc |= PORTSC_PRC | PORTSC_PED; portsc |= PORTSC_PRC | PORTSC_PED;
} }
xhci->ports[port].portsc = portsc; port->portsc = portsc;
break; break;
case 0x04: /* PORTPMSC */ case 0x04: /* PORTPMSC */
case 0x08: /* PORTLI */ case 0x08: /* PORTLI */
default: default:
fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n", fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n",
port, reg); port->portnr, (uint32_t)reg);
} }
} }
@ -2492,10 +2499,6 @@ static uint64_t xhci_oper_read(void *ptr, target_phys_addr_t reg, unsigned size)
XHCIState *xhci = ptr; XHCIState *xhci = ptr;
uint32_t ret; uint32_t ret;
if (reg >= 0x400) {
return xhci_port_read(xhci, reg - 0x400);
}
switch (reg) { switch (reg) {
case 0x00: /* USBCMD */ case 0x00: /* USBCMD */
ret = xhci->usbcmd; ret = xhci->usbcmd;
@ -2538,11 +2541,6 @@ static void xhci_oper_write(void *ptr, target_phys_addr_t reg,
{ {
XHCIState *xhci = ptr; XHCIState *xhci = ptr;
if (reg >= 0x400) {
xhci_port_write(xhci, reg - 0x400, val);
return;
}
trace_usb_xhci_oper_write(reg, val); trace_usb_xhci_oper_write(reg, val);
switch (reg) { switch (reg) {
@ -2761,6 +2759,14 @@ static const MemoryRegionOps xhci_oper_ops = {
.endianness = DEVICE_LITTLE_ENDIAN, .endianness = DEVICE_LITTLE_ENDIAN,
}; };
static const MemoryRegionOps xhci_port_ops = {
.read = xhci_port_read,
.write = xhci_port_write,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static const MemoryRegionOps xhci_runtime_ops = { static const MemoryRegionOps xhci_runtime_ops = {
.read = xhci_runtime_read, .read = xhci_runtime_read,
.write = xhci_runtime_write, .write = xhci_runtime_write,
@ -2821,12 +2827,20 @@ static void xhci_complete(USBPort *port, USBPacket *packet)
xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid); xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
} }
static void xhci_child_detach(USBPort *port, USBDevice *child) static void xhci_child_detach(USBPort *uport, USBDevice *child)
{ {
FIXME(); USBBus *bus = usb_bus_from_device(child);
XHCIState *xhci = container_of(bus, XHCIState, bus);
int i;
for (i = 0; i < MAXSLOTS; i++) {
if (xhci->slots[i].uport == uport) {
xhci->slots[i].uport = NULL;
}
}
} }
static USBPortOps xhci_port_ops = { static USBPortOps xhci_uport_ops = {
.attach = xhci_attach, .attach = xhci_attach,
.detach = xhci_detach, .detach = xhci_detach,
.wakeup = xhci_wakeup, .wakeup = xhci_wakeup,
@ -2906,6 +2920,7 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
USB_SPEED_MASK_LOW | USB_SPEED_MASK_LOW |
USB_SPEED_MASK_FULL | USB_SPEED_MASK_FULL |
USB_SPEED_MASK_HIGH; USB_SPEED_MASK_HIGH;
snprintf(port->name, sizeof(port->name), "usb2 port #%d", i+1);
speedmask |= port->speedmask; speedmask |= port->speedmask;
} }
if (i < xhci->numports_3) { if (i < xhci->numports_3) {
@ -2913,16 +2928,17 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
port->portnr = i + 1 + xhci->numports_2; port->portnr = i + 1 + xhci->numports_2;
port->uport = &xhci->uports[i]; port->uport = &xhci->uports[i];
port->speedmask = USB_SPEED_MASK_SUPER; port->speedmask = USB_SPEED_MASK_SUPER;
snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
speedmask |= port->speedmask; speedmask |= port->speedmask;
} }
usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i, usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i,
&xhci_port_ops, speedmask); &xhci_uport_ops, speedmask);
} }
} }
static int usb_xhci_initfn(struct PCIDevice *dev) static int usb_xhci_initfn(struct PCIDevice *dev)
{ {
int ret; int i, ret;
XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev); XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
@ -2941,7 +2957,7 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
memory_region_init_io(&xhci->mem_cap, &xhci_cap_ops, xhci, memory_region_init_io(&xhci->mem_cap, &xhci_cap_ops, xhci,
"capabilities", LEN_CAP); "capabilities", LEN_CAP);
memory_region_init_io(&xhci->mem_oper, &xhci_oper_ops, xhci, memory_region_init_io(&xhci->mem_oper, &xhci_oper_ops, xhci,
"operational", 0x400 + 0x10 * xhci->numports); "operational", 0x400);
memory_region_init_io(&xhci->mem_runtime, &xhci_runtime_ops, xhci, memory_region_init_io(&xhci->mem_runtime, &xhci_runtime_ops, xhci,
"runtime", LEN_RUNTIME); "runtime", LEN_RUNTIME);
memory_region_init_io(&xhci->mem_doorbell, &xhci_doorbell_ops, xhci, memory_region_init_io(&xhci->mem_doorbell, &xhci_doorbell_ops, xhci,
@ -2952,6 +2968,15 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime); memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime);
memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell); memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell);
for (i = 0; i < xhci->numports; i++) {
XHCIPort *port = &xhci->ports[i];
uint32_t offset = OFF_OPER + 0x400 + 0x10 * i;
port->xhci = xhci;
memory_region_init_io(&port->mem, &xhci_port_ops, port,
port->name, 0x10);
memory_region_add_subregion(&xhci->mem, offset, &port->mem);
}
pci_register_bar(&xhci->pci_dev, 0, pci_register_bar(&xhci->pci_dev, 0,
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
&xhci->mem); &xhci->mem);

View file

@ -28,19 +28,25 @@ int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
{ {
DMADirection dir = (p->pid == USB_TOKEN_IN) ? DMADirection dir = (p->pid == USB_TOKEN_IN) ?
DMA_DIRECTION_FROM_DEVICE : DMA_DIRECTION_TO_DEVICE; DMA_DIRECTION_FROM_DEVICE : DMA_DIRECTION_TO_DEVICE;
dma_addr_t len;
void *mem; void *mem;
int i; int i;
for (i = 0; i < sgl->nsg; i++) { for (i = 0; i < sgl->nsg; i++) {
len = sgl->sg[i].len; dma_addr_t base = sgl->sg[i].base;
mem = dma_memory_map(sgl->dma, sgl->sg[i].base, &len, dir); dma_addr_t len = sgl->sg[i].len;
if (!mem) {
goto err; while (len) {
} dma_addr_t xlen = len;
qemu_iovec_add(&p->iov, mem, len); mem = dma_memory_map(sgl->dma, sgl->sg[i].base, &xlen, dir);
if (len != sgl->sg[i].len) { if (!mem) {
goto err; goto err;
}
if (xlen > len) {
xlen = len;
}
qemu_iovec_add(&p->iov, mem, xlen);
len -= xlen;
base += xlen;
} }
} }
return 0; return 0;