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:
		
						commit
						938406dfb1
					
				
							
								
								
									
										6
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@ -2748,10 +2748,10 @@ fi
 | 
			
		||||
 | 
			
		||||
# check for usbredirparser for usb network redirection support
 | 
			
		||||
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_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
 | 
			
		||||
        usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
 | 
			
		||||
        usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null)
 | 
			
		||||
        usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null)
 | 
			
		||||
        QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
 | 
			
		||||
        libs_softmmu="$libs_softmmu $usb_redir_libs"
 | 
			
		||||
    else
 | 
			
		||||
 | 
			
		||||
@ -373,6 +373,7 @@ struct EHCIQueue {
 | 
			
		||||
    uint32_t seen;
 | 
			
		||||
    uint64_t ts;
 | 
			
		||||
    int async;
 | 
			
		||||
    int transact_ctr;
 | 
			
		||||
 | 
			
		||||
    /* cached data from guest - needs to be flushed
 | 
			
		||||
     * 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->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) {
 | 
			
		||||
        q->dev = ehci_find_device(q->ehci, devaddr);
 | 
			
		||||
    }
 | 
			
		||||
@ -2014,11 +2020,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
 | 
			
		||||
    } else if (p != NULL) {
 | 
			
		||||
        switch (p->async) {
 | 
			
		||||
        case EHCI_ASYNC_NONE:
 | 
			
		||||
            /* Should never happen packet should at least be initialized */
 | 
			
		||||
            assert(0);
 | 
			
		||||
            break;
 | 
			
		||||
        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);
 | 
			
		||||
            break;
 | 
			
		||||
        case EHCI_ASYNC_INFLIGHT:
 | 
			
		||||
@ -2107,16 +2110,13 @@ static int ehci_state_execute(EHCIQueue *q)
 | 
			
		||||
 | 
			
		||||
    // 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 Windows does not seem to ever set the MULT field
 | 
			
		||||
 | 
			
		||||
    if (!q->async) {
 | 
			
		||||
        int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
 | 
			
		||||
        if (!transactCtr) {
 | 
			
		||||
    /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
 | 
			
		||||
    if (!q->async && q->transact_ctr == 0) {
 | 
			
		||||
        ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
 | 
			
		||||
        again = 1;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (q->async) {
 | 
			
		||||
        ehci_set_usbsts(q->ehci, USBSTS_REC);
 | 
			
		||||
@ -2132,7 +2132,11 @@ static int ehci_state_execute(EHCIQueue *q)
 | 
			
		||||
        trace_usb_ehci_packet_action(p->queue, p, "async");
 | 
			
		||||
        p->async = EHCI_ASYNC_INFLIGHT;
 | 
			
		||||
        ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
 | 
			
		||||
        if (q->async) {
 | 
			
		||||
            again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
 | 
			
		||||
        } else {
 | 
			
		||||
            again = 1;
 | 
			
		||||
        }
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2152,13 +2156,9 @@ static int ehci_state_executing(EHCIQueue *q)
 | 
			
		||||
 | 
			
		||||
    ehci_execute_complete(q);
 | 
			
		||||
 | 
			
		||||
    // 4.10.3
 | 
			
		||||
    if (!q->async) {
 | 
			
		||||
        int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
 | 
			
		||||
        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.3 */
 | 
			
		||||
    if (!q->async && q->transact_ctr > 0) {
 | 
			
		||||
        q->transact_ctr--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 4.10.5 */
 | 
			
		||||
 | 
			
		||||
@ -37,12 +37,12 @@
 | 
			
		||||
#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
 | 
			
		||||
                             __func__, __LINE__); abort(); } while (0)
 | 
			
		||||
 | 
			
		||||
#define MAXPORTS_2 8
 | 
			
		||||
#define MAXPORTS_3 8
 | 
			
		||||
#define MAXPORTS_2 15
 | 
			
		||||
#define MAXPORTS_3 15
 | 
			
		||||
 | 
			
		||||
#define MAXPORTS (MAXPORTS_2+MAXPORTS_3)
 | 
			
		||||
#define MAXSLOTS MAXPORTS
 | 
			
		||||
#define MAXINTRS MAXPORTS
 | 
			
		||||
#define MAXSLOTS 64
 | 
			
		||||
#define MAXINTRS 16
 | 
			
		||||
 | 
			
		||||
#define TD_QUEUE 24
 | 
			
		||||
 | 
			
		||||
@ -285,6 +285,8 @@ typedef enum TRBCCode {
 | 
			
		||||
#define SLOT_CONTEXT_ENTRIES_MASK 0x1f
 | 
			
		||||
#define SLOT_CONTEXT_ENTRIES_SHIFT 27
 | 
			
		||||
 | 
			
		||||
typedef struct XHCIState XHCIState;
 | 
			
		||||
 | 
			
		||||
typedef enum EPType {
 | 
			
		||||
    ET_INVALID = 0,
 | 
			
		||||
    ET_ISO_OUT,
 | 
			
		||||
@ -303,15 +305,15 @@ typedef struct XHCIRing {
 | 
			
		||||
} XHCIRing;
 | 
			
		||||
 | 
			
		||||
typedef struct XHCIPort {
 | 
			
		||||
    XHCIState *xhci;
 | 
			
		||||
    uint32_t portsc;
 | 
			
		||||
    uint32_t portnr;
 | 
			
		||||
    USBPort  *uport;
 | 
			
		||||
    uint32_t speedmask;
 | 
			
		||||
    char name[16];
 | 
			
		||||
    MemoryRegion mem;
 | 
			
		||||
} XHCIPort;
 | 
			
		||||
 | 
			
		||||
struct XHCIState;
 | 
			
		||||
typedef struct XHCIState XHCIState;
 | 
			
		||||
 | 
			
		||||
typedef struct XHCITransfer {
 | 
			
		||||
    XHCIState *xhci;
 | 
			
		||||
    USBPacket packet;
 | 
			
		||||
@ -363,7 +365,7 @@ typedef struct XHCIEPContext {
 | 
			
		||||
typedef struct XHCISlot {
 | 
			
		||||
    bool enabled;
 | 
			
		||||
    dma_addr_t ctx;
 | 
			
		||||
    unsigned int port;
 | 
			
		||||
    USBPort *uport;
 | 
			
		||||
    unsigned int devaddr;
 | 
			
		||||
    XHCIEPContext * eps[31];
 | 
			
		||||
} XHCISlot;
 | 
			
		||||
@ -1230,7 +1232,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
 | 
			
		||||
        ep |= 0x80;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dev = xhci->ports[xhci->slots[slotid-1].port-1].uport->dev;
 | 
			
		||||
    dev = xhci->slots[slotid-1].uport->dev;
 | 
			
		||||
    if (!dev) {
 | 
			
		||||
        return CC_USB_TRANSACTION_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
@ -1412,18 +1414,9 @@ static void xhci_stall_ep(XHCITransfer *xfer)
 | 
			
		||||
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
 | 
			
		||||
                       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)
 | 
			
		||||
{
 | 
			
		||||
    XHCIState *xhci = xfer->xhci;
 | 
			
		||||
    XHCIPort *port;
 | 
			
		||||
    USBDevice *dev;
 | 
			
		||||
    USBEndpoint *ep;
 | 
			
		||||
    int dir;
 | 
			
		||||
@ -1434,13 +1427,12 @@ static int xhci_setup_packet(XHCITransfer *xfer)
 | 
			
		||||
        ep = xfer->packet.ep;
 | 
			
		||||
        dev = ep->dev;
 | 
			
		||||
    } else {
 | 
			
		||||
        port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
 | 
			
		||||
        dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
 | 
			
		||||
        if (!dev) {
 | 
			
		||||
            fprintf(stderr, "xhci: slot %d port %d has no device\n",
 | 
			
		||||
                    xfer->slotid, xhci->slots[xfer->slotid-1].port);
 | 
			
		||||
        if (!xhci->slots[xfer->slotid-1].uport) {
 | 
			
		||||
            fprintf(stderr, "xhci: slot %d has no device\n",
 | 
			
		||||
                    xfer->slotid);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        dev = xhci->slots[xfer->slotid-1].uport->dev;
 | 
			
		||||
        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);
 | 
			
		||||
    assert(slotid >= 1 && slotid <= MAXSLOTS);
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    return CC_SUCCESS;
 | 
			
		||||
@ -1795,17 +1787,42 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
 | 
			
		||||
    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,
 | 
			
		||||
                                  uint64_t pictx, bool bsr)
 | 
			
		||||
{
 | 
			
		||||
    XHCISlot *slot;
 | 
			
		||||
    USBPort *uport;
 | 
			
		||||
    USBDevice *dev;
 | 
			
		||||
    dma_addr_t ictx, octx, dcbaap;
 | 
			
		||||
    uint64_t poctx;
 | 
			
		||||
    uint32_t ictl_ctx[2];
 | 
			
		||||
    uint32_t slot_ctx[4];
 | 
			
		||||
    uint32_t ep0_ctx[5];
 | 
			
		||||
    unsigned int port;
 | 
			
		||||
    int i;
 | 
			
		||||
    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",
 | 
			
		||||
            ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
 | 
			
		||||
 | 
			
		||||
    port = (slot_ctx[1]>>16) & 0xFF;
 | 
			
		||||
    dev = xhci->ports[port-1].uport->dev;
 | 
			
		||||
 | 
			
		||||
    if (port < 1 || port > xhci->numports) {
 | 
			
		||||
        fprintf(stderr, "xhci: bad port %d\n", port);
 | 
			
		||||
    uport = xhci_lookup_uport(xhci, slot_ctx);
 | 
			
		||||
    if (uport == NULL) {
 | 
			
		||||
        fprintf(stderr, "xhci: port not found\n");
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < MAXSLOTS; i++) {
 | 
			
		||||
        if (xhci->slots[i].port == port) {
 | 
			
		||||
            fprintf(stderr, "xhci: port %d already assigned to slot %d\n",
 | 
			
		||||
                    port, i+1);
 | 
			
		||||
        if (xhci->slots[i].uport == uport) {
 | 
			
		||||
            fprintf(stderr, "xhci: port %s already assigned to slot %d\n",
 | 
			
		||||
                    uport->path, i+1);
 | 
			
		||||
            return CC_TRB_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    slot = &xhci->slots[slotid-1];
 | 
			
		||||
    slot->port = port;
 | 
			
		||||
    slot->uport = uport;
 | 
			
		||||
    slot->ctx = octx;
 | 
			
		||||
 | 
			
		||||
    if (bsr) {
 | 
			
		||||
@ -2414,20 +2432,14 @@ static uint64_t xhci_cap_read(void *ptr, target_phys_addr_t reg, unsigned size)
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    if (port >= xhci->numports) {
 | 
			
		||||
        fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
 | 
			
		||||
        ret = 0;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (reg & 0xf) {
 | 
			
		||||
    switch (reg) {
 | 
			
		||||
    case 0x00: /* PORTSC */
 | 
			
		||||
        ret = xhci->ports[port].portsc;
 | 
			
		||||
        ret = port->portsc;
 | 
			
		||||
        break;
 | 
			
		||||
    case 0x04: /* PORTPMSC */
 | 
			
		||||
    case 0x08: /* PORTLI */
 | 
			
		||||
@ -2436,30 +2448,25 @@ static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg)
 | 
			
		||||
    case 0x0c: /* reserved */
 | 
			
		||||
    default:
 | 
			
		||||
        fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
 | 
			
		||||
                port, reg);
 | 
			
		||||
                port->portnr, (uint32_t)reg);
 | 
			
		||||
        ret = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    trace_usb_xhci_port_read(port, reg & 0x0f, ret);
 | 
			
		||||
    trace_usb_xhci_port_read(port->portnr, reg, 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;
 | 
			
		||||
 | 
			
		||||
    trace_usb_xhci_port_write(port, reg & 0x0f, val);
 | 
			
		||||
    trace_usb_xhci_port_write(port->portnr, reg, val);
 | 
			
		||||
 | 
			
		||||
    if (port >= xhci->numports) {
 | 
			
		||||
        fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (reg & 0xf) {
 | 
			
		||||
    switch (reg) {
 | 
			
		||||
    case 0x00: /* PORTSC */
 | 
			
		||||
        portsc = xhci->ports[port].portsc;
 | 
			
		||||
        portsc = port->portsc;
 | 
			
		||||
        /* write-1-to-clear bits*/
 | 
			
		||||
        portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC|
 | 
			
		||||
                           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 */
 | 
			
		||||
        if (val & PORTSC_PR) {
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
        xhci->ports[port].portsc = portsc;
 | 
			
		||||
        port->portsc = portsc;
 | 
			
		||||
        break;
 | 
			
		||||
    case 0x04: /* PORTPMSC */
 | 
			
		||||
    case 0x08: /* PORTLI */
 | 
			
		||||
    default:
 | 
			
		||||
        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;
 | 
			
		||||
    uint32_t ret;
 | 
			
		||||
 | 
			
		||||
    if (reg >= 0x400) {
 | 
			
		||||
        return xhci_port_read(xhci, reg - 0x400);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (reg) {
 | 
			
		||||
    case 0x00: /* USBCMD */
 | 
			
		||||
        ret = xhci->usbcmd;
 | 
			
		||||
@ -2538,11 +2541,6 @@ static void xhci_oper_write(void *ptr, target_phys_addr_t reg,
 | 
			
		||||
{
 | 
			
		||||
    XHCIState *xhci = ptr;
 | 
			
		||||
 | 
			
		||||
    if (reg >= 0x400) {
 | 
			
		||||
        xhci_port_write(xhci, reg - 0x400, val);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    trace_usb_xhci_oper_write(reg, val);
 | 
			
		||||
 | 
			
		||||
    switch (reg) {
 | 
			
		||||
@ -2761,6 +2759,14 @@ static const MemoryRegionOps xhci_oper_ops = {
 | 
			
		||||
    .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 = {
 | 
			
		||||
    .read = xhci_runtime_read,
 | 
			
		||||
    .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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
    .detach   = xhci_detach,
 | 
			
		||||
    .wakeup   = xhci_wakeup,
 | 
			
		||||
@ -2906,6 +2920,7 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
 | 
			
		||||
                USB_SPEED_MASK_LOW  |
 | 
			
		||||
                USB_SPEED_MASK_FULL |
 | 
			
		||||
                USB_SPEED_MASK_HIGH;
 | 
			
		||||
            snprintf(port->name, sizeof(port->name), "usb2 port #%d", i+1);
 | 
			
		||||
            speedmask |= port->speedmask;
 | 
			
		||||
        }
 | 
			
		||||
        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->uport = &xhci->uports[i];
 | 
			
		||||
            port->speedmask = USB_SPEED_MASK_SUPER;
 | 
			
		||||
            snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
 | 
			
		||||
            speedmask |= port->speedmask;
 | 
			
		||||
        }
 | 
			
		||||
        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)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    int i, ret;
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
                          "capabilities", LEN_CAP);
 | 
			
		||||
    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,
 | 
			
		||||
                          "runtime", LEN_RUNTIME);
 | 
			
		||||
    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_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_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
 | 
			
		||||
                     &xhci->mem);
 | 
			
		||||
 | 
			
		||||
@ -28,19 +28,25 @@ int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
 | 
			
		||||
{
 | 
			
		||||
    DMADirection dir = (p->pid == USB_TOKEN_IN) ?
 | 
			
		||||
        DMA_DIRECTION_FROM_DEVICE : DMA_DIRECTION_TO_DEVICE;
 | 
			
		||||
    dma_addr_t len;
 | 
			
		||||
    void *mem;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < sgl->nsg; i++) {
 | 
			
		||||
        len = sgl->sg[i].len;
 | 
			
		||||
        mem = dma_memory_map(sgl->dma, sgl->sg[i].base, &len, dir);
 | 
			
		||||
        dma_addr_t base = sgl->sg[i].base;
 | 
			
		||||
        dma_addr_t len = sgl->sg[i].len;
 | 
			
		||||
 | 
			
		||||
        while (len) {
 | 
			
		||||
            dma_addr_t xlen = len;
 | 
			
		||||
            mem = dma_memory_map(sgl->dma, sgl->sg[i].base, &xlen, dir);
 | 
			
		||||
            if (!mem) {
 | 
			
		||||
                goto err;
 | 
			
		||||
            }
 | 
			
		||||
        qemu_iovec_add(&p->iov, mem, len);
 | 
			
		||||
        if (len != sgl->sg[i].len) {
 | 
			
		||||
            goto err;
 | 
			
		||||
            if (xlen > len) {
 | 
			
		||||
                xlen = len;
 | 
			
		||||
            }
 | 
			
		||||
            qemu_iovec_add(&p->iov, mem, xlen);
 | 
			
		||||
            len -= xlen;
 | 
			
		||||
            base += xlen;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user