Commit cfb75cb9 authored by Aurelien Jarno's avatar Aurelien Jarno
Browse files

Merge branch 'usb.65' of git://git.kraxel.org/qemu

* 'usb.65' of git://git.kraxel.org/qemu:
  uhci: Don't queue up packets after one with the SPD flag set
  usb-redir: Revert usb-redir part of commit 93bfef4c
  usb-redir: Add chardev open / close debug logging
  usb-redir: Add support for migration
  usb-redir: Store max_packet_size in endp_data
  usb-redir: Add an already_in_flight packet-id queue
  usb-redir: Change cancelled packet code into a generic packet-id queue
  ehci: Walk async schedule before and after migration
  ehci: Don't set seen to 0 when removing unseen queue-heads
  configure: usbredir fixes
  ehci: Don't process too much frames in 1 timer tick (v2)
  ehci: Fix interrupts stopping when Interrupt Threshold Control is 8
  ehci: switch to new-style memory ops
  usb-host: allow emulated (non-async) control requests without USBPacket
parents e55f523d 72a04d0c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2795,7 +2795,7 @@ if test "$usb_redir" != "no" ; then
        usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
        usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
        QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
        LIBS="$LIBS $usb_redir_libs"
        libs_softmmu="$libs_softmmu $usb_redir_libs"
    else
        if test "$usb_redir" = "yes"; then
            feature_not_found "usb-redir"
+145 −96
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include "monitor.h"
#include "trace.h"
#include "dma.h"
#include "sysemu.h"

#define EHCI_DEBUG   0

@@ -139,6 +140,7 @@
#define NB_PORTS         6        // Number of downstream ports
#define BUFF_SIZE        5*4096   // Max bytes to transfer per transaction
#define MAX_QH           100      // Max allowable queue heads in a chain
#define MIN_FR_PER_TICK  3        // Min frames to process when catching up

/*  Internal periodic / asynchronous schedule state machine states
 */
@@ -389,6 +391,9 @@ struct EHCIState {
    USBBus bus;
    qemu_irq irq;
    MemoryRegion mem;
    MemoryRegion mem_caps;
    MemoryRegion mem_opreg;
    MemoryRegion mem_ports;
    int companion_count;

    /* properties */
@@ -398,10 +403,10 @@ struct EHCIState {
     *  EHCI spec version 1.0 Section 2.3
     *  Host Controller Operational Registers
     */
    uint8_t caps[OPREGBASE];
    union {
        uint8_t mmio[MMIO_SIZE];
        uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)];
        struct {
            uint8_t cap[OPREGBASE];
            uint32_t usbcmd;
            uint32_t usbsts;
            uint32_t usbintr;
@@ -411,9 +416,9 @@ struct EHCIState {
            uint32_t asynclistaddr;
            uint32_t notused[9];
            uint32_t configflag;
            uint32_t portsc[NB_PORTS];
        };
    };
    uint32_t portsc[NB_PORTS];

    /*
     *  Internal states, shadow registers, etc
@@ -471,22 +476,12 @@ static const char *ehci_state_names[] = {
};

static const char *ehci_mmio_names[] = {
    [CAPLENGTH]         = "CAPLENGTH",
    [HCIVERSION]        = "HCIVERSION",
    [HCSPARAMS]         = "HCSPARAMS",
    [HCCPARAMS]         = "HCCPARAMS",
    [USBCMD]            = "USBCMD",
    [USBSTS]            = "USBSTS",
    [USBINTR]           = "USBINTR",
    [FRINDEX]           = "FRINDEX",
    [PERIODICLISTBASE]  = "P-LIST BASE",
    [ASYNCLISTADDR]     = "A-LIST ADDR",
    [PORTSC_BEGIN]      = "PORTSC #0",
    [PORTSC_BEGIN + 4]  = "PORTSC #1",
    [PORTSC_BEGIN + 8]  = "PORTSC #2",
    [PORTSC_BEGIN + 12] = "PORTSC #3",
    [PORTSC_BEGIN + 16] = "PORTSC #4",
    [PORTSC_BEGIN + 20] = "PORTSC #5",
    [CONFIGFLAG]        = "CONFIGFLAG",
};

@@ -509,7 +504,8 @@ static const char *state2str(uint32_t state)

static const char *addr2str(target_phys_addr_t addr)
{
    return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
    return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names),
                  addr + OPREGBASE);
}

static void ehci_trace_usbsts(uint32_t mask, int state)
@@ -853,10 +849,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
    return NULL;
}

static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
static void ehci_queues_rip_unused(EHCIState *ehci, int async)
{
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
    const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL;
    const char *warn = async ? "guest unlinked busy QH" : NULL;
    uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
    EHCIQueue *q, *tmp;

@@ -866,13 +862,25 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
            q->ts = ehci->last_run_ns;
            continue;
        }
        if (!flush && ehci->last_run_ns < q->ts + maxage) {
        if (ehci->last_run_ns < q->ts + maxage) {
            continue;
        }
        ehci_free_queue(q, warn);
    }
}

static void ehci_queues_rip_unseen(EHCIState *ehci, int async)
{
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
    EHCIQueue *q, *tmp;

    QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
        if (!q->seen) {
            ehci_free_queue(q, NULL);
        }
    }
}

static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
{
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
@@ -1018,7 +1026,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
    }

    s->companion_count++;
    s->mmio[0x05] = (s->companion_count << 4) | portcount;
    s->caps[0x05] = (s->companion_count << 4) | portcount;

    return 0;
}
@@ -1063,7 +1071,8 @@ static void ehci_reset(void *opaque)
        }
    }

    memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
    memset(&s->opreg, 0x00, sizeof(s->opreg));
    memset(&s->portsc, 0x00, sizeof(s->portsc));

    s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
    s->usbsts = USBSTS_HALT;
@@ -1090,50 +1099,35 @@ static void ehci_reset(void *opaque)
    qemu_bh_cancel(s->async_bh);
}

static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr,
                               unsigned size)
{
    EHCIState *s = ptr;
    uint32_t val;

    val = s->mmio[addr];

    return val;
    return s->caps[addr];
}

static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr)
static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr,
                                unsigned size)
{
    EHCIState *s = ptr;
    uint32_t val;

    val = s->mmio[addr] | (s->mmio[addr+1] << 8);

    val = s->opreg[addr >> 2];
    trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val);
    return val;
}

static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr,
                               unsigned size)
{
    EHCIState *s = ptr;
    uint32_t val;

    val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
          (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);

    trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
    val = s->portsc[addr >> 2];
    trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val);
    return val;
}

static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val)
{
    fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n");
    exit(1);
}

static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
{
    fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n");
    exit(1);
}

static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
{
    USBDevice *dev = s->ports[port].dev;
@@ -1162,11 +1156,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
    }
}

static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
static void ehci_port_write(void *ptr, target_phys_addr_t addr,
                            uint64_t val, unsigned size)
{
    EHCIState *s = ptr;
    int port = addr >> 2;
    uint32_t *portsc = &s->portsc[port];
    uint32_t old = *portsc;
    USBDevice *dev = s->ports[port].dev;

    trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val);

    /* Clear rwc bits */
    *portsc &= ~(val & PORTSC_RWC_MASK);
    /* The guest may clear, but not set the PED bit */
@@ -1198,39 +1198,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)

    *portsc &= ~PORTSC_RO_MASK;
    *portsc |= val;
    trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old);
}

static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
static void ehci_opreg_write(void *ptr, target_phys_addr_t addr,
                             uint64_t val, unsigned size)
{
    EHCIState *s = ptr;
    uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
    uint32_t *mmio = s->opreg + (addr >> 2);
    uint32_t old = *mmio;
    int i;

    trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);

    /* Only aligned reads are allowed on OHCI */
    if (addr & 3) {
        fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x"
                TARGET_FMT_plx "\n", addr);
        return;
    }

    if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
        handle_port_status_write(s, (addr-PORTSC)/4, val);
        trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
        return;
    }

    if (addr < OPREGBASE) {
        fprintf(stderr, "usb-ehci: write attempt to read-only register"
                TARGET_FMT_plx "\n", addr);
        return;
    }

    trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val);

    /* Do any register specific pre-write processing here.  */
    switch(addr) {
    switch (addr + OPREGBASE) {
    case USBCMD:
        if (val & USBCMD_HCRESET) {
            ehci_reset(s);
@@ -1241,7 +1222,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
        /* not supporting dynamic frame list size at the moment */
        if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
            fprintf(stderr, "attempt to set frame list size -- value %d\n",
                    val & USBCMD_FLS);
                    (int)val & USBCMD_FLS);
            val &= ~USBCMD_FLS;
        }

@@ -1308,7 +1289,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
    }

    *mmio = val;
    trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
    trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old);
}


@@ -1732,7 +1713,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
        ehci_set_usbsts(ehci, USBSTS_REC);
    }

    ehci_queues_rip_unused(ehci, async, 0);
    ehci_queues_rip_unused(ehci, async);

    /*  Find the head of the list (4.9.1.1) */
    for(i = 0; i < MAX_QH; i++) {
@@ -2364,7 +2345,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
         */
        if (ehci->usbcmd & USBCMD_IAAD) {
            /* Remove all unseen qhs from the async qhs queue */
            ehci_queues_rip_unused(ehci, async, 1);
            ehci_queues_rip_unseen(ehci, async);
            trace_usb_ehci_doorbell_ack();
            ehci->usbcmd &= ~USBCMD_IAAD;
            ehci_raise_irq(ehci, USBSTS_IAA);
@@ -2417,7 +2398,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
        ehci_set_fetch_addr(ehci, async,entry);
        ehci_set_state(ehci, async, EST_FETCHENTRY);
        ehci_advance_state(ehci, async);
        ehci_queues_rip_unused(ehci, async, 0);
        ehci_queues_rip_unused(ehci, async);
        break;

    default:
@@ -2446,7 +2427,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames)
        if (ehci->frindex == 0x00004000) {
            ehci_raise_irq(ehci, USBSTS_FLR);
            ehci->frindex = 0;
            if (ehci->usbsts_frindex > 0x00004000) {
            if (ehci->usbsts_frindex >= 0x00004000) {
                ehci->usbsts_frindex -= 0x00004000;
            } else {
                ehci->usbsts_frindex = 0;
@@ -2481,6 +2462,19 @@ static void ehci_frame_timer(void *opaque)
        }

        for (i = 0; i < frames; i++) {
            /*
             * If we're running behind schedule, we should not catch up
             * too fast, as that will make some guests unhappy:
             * 1) We must process a minimum of MIN_FR_PER_TICK frames,
             *    otherwise we will never catch up
             * 2) Process frames until the guest has requested an irq (IOC)
             */
            if (i >= MIN_FR_PER_TICK) {
                ehci_commit_irq(ehci);
                if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) {
                    break;
                }
            }
            ehci_update_frindex(ehci, 1);
            ehci_advance_periodic_state(ehci);
            ehci->last_run_ns += FRAME_TIMER_NS;
@@ -2520,11 +2514,28 @@ static void ehci_async_bh(void *opaque)
    ehci_advance_async_state(ehci);
}

static const MemoryRegionOps ehci_mem_ops = {
    .old_mmio = {
        .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl },
        .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel },
    },
static const MemoryRegionOps ehci_mmio_caps_ops = {
    .read = ehci_caps_read,
    .valid.min_access_size = 1,
    .valid.max_access_size = 4,
    .impl.min_access_size = 1,
    .impl.max_access_size = 1,
    .endianness = DEVICE_LITTLE_ENDIAN,
};

static const MemoryRegionOps ehci_mmio_opreg_ops = {
    .read = ehci_opreg_read,
    .write = ehci_opreg_write,
    .valid.min_access_size = 4,
    .valid.max_access_size = 4,
    .endianness = DEVICE_LITTLE_ENDIAN,
};

static const MemoryRegionOps ehci_mmio_port_ops = {
    .read = ehci_port_read,
    .write = ehci_port_write,
    .valid.min_access_size = 4,
    .valid.max_access_size = 4,
    .endianness = DEVICE_LITTLE_ENDIAN,
};

@@ -2562,6 +2573,32 @@ static int usb_ehci_post_load(void *opaque, int version_id)
    return 0;
}

static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
{
    EHCIState *ehci = opaque;

    /*
     * We don't migrate the EHCIQueue-s, instead we rebuild them for the
     * schedule in guest memory. We must do the rebuilt ASAP, so that
     * USB-devices which have async handled packages have a packet in the
     * ep queue to match the completion with.
     */
    if (state == RUN_STATE_RUNNING) {
        ehci_advance_async_state(ehci);
    }

    /*
     * The schedule rebuilt from guest memory could cause the migration dest
     * to miss a QH unlink, and fail to cancel packets, since the unlinked QH
     * will never have existed on the destination. Therefor we must flush the
     * async schedule on savevm to catch any not yet noticed unlinks.
     */
    if (state == RUN_STATE_SAVE_VM) {
        ehci_advance_async_state(ehci);
        ehci_queues_rip_unseen(ehci, 1);
    }
}

static const VMStateDescription vmstate_ehci = {
    .name        = "ehci",
    .version_id  = 2,
@@ -2681,19 +2718,19 @@ static int usb_ehci_initfn(PCIDevice *dev)
    pci_conf[0x6e] = 0x00;
    pci_conf[0x6f] = 0xc0;  // USBLEFCTLSTS

    // 2.2 host controller interface version
    s->mmio[0x00] = (uint8_t) OPREGBASE;
    s->mmio[0x01] = 0x00;
    s->mmio[0x02] = 0x00;
    s->mmio[0x03] = 0x01;        // HC version
    s->mmio[0x04] = NB_PORTS;    // Number of downstream ports
    s->mmio[0x05] = 0x00;        // No companion ports at present
    s->mmio[0x06] = 0x00;
    s->mmio[0x07] = 0x00;
    s->mmio[0x08] = 0x80;        // We can cache whole frame, not 64-bit capable
    s->mmio[0x09] = 0x68;        // EECP
    s->mmio[0x0a] = 0x00;
    s->mmio[0x0b] = 0x00;
    /* 2.2 host controller interface version */
    s->caps[0x00] = (uint8_t) OPREGBASE;
    s->caps[0x01] = 0x00;
    s->caps[0x02] = 0x00;
    s->caps[0x03] = 0x01;        /* HC version */
    s->caps[0x04] = NB_PORTS;    /* Number of downstream ports */
    s->caps[0x05] = 0x00;        /* No companion ports at present */
    s->caps[0x06] = 0x00;
    s->caps[0x07] = 0x00;
    s->caps[0x08] = 0x80;        /* We can cache whole frame, no 64-bit */
    s->caps[0x09] = 0x68;        /* EECP */
    s->caps[0x0a] = 0x00;
    s->caps[0x0b] = 0x00;

    s->irq = s->dev.irq[3];

@@ -2711,8 +2748,20 @@ static int usb_ehci_initfn(PCIDevice *dev)
    usb_packet_init(&s->ipacket);

    qemu_register_reset(ehci_reset, s);
    qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);

    memory_region_init(&s->mem, "ehci", MMIO_SIZE);
    memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s,
                          "capabilities", OPREGBASE);
    memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s,
                          "operational", PORTSC_BEGIN - OPREGBASE);
    memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s,
                          "ports", PORTSC_END - PORTSC_BEGIN);

    memory_region_add_subregion(&s->mem, 0,            &s->mem_caps);
    memory_region_add_subregion(&s->mem, OPREGBASE,    &s->mem_opreg);
    memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports);

    memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE);
    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);

    return 0;
+4 −1
Original line number Diff line number Diff line
@@ -1000,6 +1000,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
        }
        assert(ret == TD_RESULT_ASYNC_START);
        assert(int_mask == 0);
        if (ptd.ctrl & TD_CTRL_SPD) {
            break;
        }
        plink = ptd.link;
    }
}
@@ -1097,7 +1100,7 @@ static void uhci_process_frame(UHCIState *s)

        case TD_RESULT_ASYNC_START:
            trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
            if (is_valid(td.link)) {
            if (is_valid(td.link) && !(td.ctrl & TD_CTRL_SPD)) {
                uhci_fill_queue(s, &td);
            }
            link = curr_qh ? qh.link : td.link;
+1 −1
Original line number Diff line number Diff line
@@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,

    /* Note request is (bRequestType << 8) | bRequest */
    trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
    assert(p->result == 0);

    switch (request) {
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
@@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
    }

    /* The rest are asynchronous */
    assert(p && p->result == 0);

    if (length > sizeof(dev->data_buf)) {
        fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
+468 −36

File changed.

Preview size limit exceeded, changes collapsed.

Loading