提交 6b0e6468 编写于 作者: A Anthony Liguori

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

* kraxel/usb.68: (36 commits)
  xhci: fix usb name in caps
  xhci: make number of interrupters and slots configurable
  xhci: allow disabling interrupters
  xhci: flush endpoint context unconditinally
  xhci: fix function name in error message
  uhci: Use only one queue for ctrl endpoints
  uhci: Retry to fill the queue while waiting for td completion
  uhci: Always mark a queue valid when we encounter it
  uhci: When the guest marks a pending td non-active, cancel the queue
  uhci: Detect guest td re-use
  uhci: Verify queue has not been changed by guest
  uhci: Immediately free queues on device disconnect
  uhci: Store ep in UHCIQueue
  uhci: Make uhci_fill_queue() actually operate on an UHCIQueue
  uhci: Add uhci_read_td() helper function
  uhci: Rename UHCIAsync->td to UHCIAsync->td_addr
  uhci: Move emptying of the queue's asyncs' queue to uhci_queue_free
  uhci: Drop unnecessary forward declaration of some static functions
  uhci: Don't retry on error
  uhci: cleanup: Add an unlink call to uhci_async_cancel()
  ...
Signed-off-by: NAnthony Liguori <aliguori@us.ibm.com>
......@@ -38,12 +38,14 @@
#define USB_TOKEN_IN 0x69 /* device -> host */
#define USB_TOKEN_OUT 0xe1 /* host -> device */
#define USB_RET_NODEV (-1)
#define USB_RET_NAK (-2)
#define USB_RET_STALL (-3)
#define USB_RET_BABBLE (-4)
#define USB_RET_IOERROR (-5)
#define USB_RET_ASYNC (-6)
#define USB_RET_NODEV (-1)
#define USB_RET_NAK (-2)
#define USB_RET_STALL (-3)
#define USB_RET_BABBLE (-4)
#define USB_RET_IOERROR (-5)
#define USB_RET_ASYNC (-6)
#define USB_RET_ADD_TO_QUEUE (-7)
#define USB_RET_REMOVE_FROM_QUEUE (-8)
#define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1
......@@ -293,6 +295,12 @@ typedef struct USBDeviceClass {
void (*set_interface)(USBDevice *dev, int interface,
int alt_old, int alt_new);
/*
* Called when the hcd is done queuing packets for an endpoint, only
* necessary for devices which can return USB_RET_ADD_TO_QUEUE.
*/
void (*flush_ep_queue)(USBDevice *dev, USBEndpoint *ep);
const char *product_desc;
const USBDesc *usb_desc;
} USBDeviceClass;
......@@ -343,6 +351,8 @@ struct USBPacket {
USBEndpoint *ep;
QEMUIOVector iov;
uint64_t parameter; /* control transfers */
bool short_not_ok;
bool int_req;
int result; /* transfer length or USB_RET_* status code */
/* Internal use by the USB layer. */
USBPacketState state;
......@@ -352,7 +362,8 @@ struct USBPacket {
void usb_packet_init(USBPacket *p);
void usb_packet_set_state(USBPacket *p, USBPacketState state);
void usb_packet_check_state(USBPacket *p, USBPacketState expected);
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id);
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
bool short_not_ok, bool int_req);
void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl);
......@@ -370,6 +381,7 @@ USBDevice *usb_find_device(USBPort *port, uint8_t addr);
int usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_packet_complete_one(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
void usb_ep_init(USBDevice *dev);
......@@ -506,6 +518,8 @@ int usb_device_handle_data(USBDevice *dev, USBPacket *p);
void usb_device_set_interface(USBDevice *dev, int interface,
int alt_old, int alt_new);
void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep);
const char *usb_device_get_product_desc(USBDevice *dev);
const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
......
......@@ -181,6 +181,14 @@ void usb_device_set_interface(USBDevice *dev, int interface,
}
}
void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
if (klass->flush_ep_queue) {
klass->flush_ep_queue(dev, ep);
}
}
static int usb_qdev_init(DeviceState *qdev)
{
USBDevice *dev = USB_DEVICE(qdev);
......
......@@ -391,8 +391,13 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
ret = usb_process_one(p);
if (ret == USB_RET_ASYNC) {
assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
usb_packet_set_state(p, USB_PACKET_ASYNC);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
} else if (ret == USB_RET_ADD_TO_QUEUE) {
usb_packet_set_state(p, USB_PACKET_QUEUED);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
ret = USB_RET_ASYNC;
} else {
/*
* When pipelining is enabled usb-devices must always return async,
......@@ -412,13 +417,14 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
return ret;
}
static void __usb_packet_complete(USBDevice *dev, USBPacket *p)
void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
{
USBEndpoint *ep = p->ep;
assert(QTAILQ_FIRST(&ep->queue) == p);
assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);
if (p->result < 0) {
if (p->result < 0 || (p->short_not_ok && (p->result < p->iov.size))) {
ep->halted = true;
}
usb_packet_set_state(p, USB_PACKET_COMPLETE);
......@@ -435,11 +441,16 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
int ret;
usb_packet_check_state(p, USB_PACKET_ASYNC);
assert(QTAILQ_FIRST(&ep->queue) == p);
__usb_packet_complete(dev, p);
usb_packet_complete_one(dev, p);
while (!ep->halted && !QTAILQ_EMPTY(&ep->queue)) {
while (!QTAILQ_EMPTY(&ep->queue)) {
p = QTAILQ_FIRST(&ep->queue);
if (ep->halted) {
/* Empty the queue on a halt */
p->result = USB_RET_REMOVE_FROM_QUEUE;
dev->port->ops->complete(dev->port, p);
continue;
}
if (p->state == USB_PACKET_ASYNC) {
break;
}
......@@ -450,7 +461,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
break;
}
p->result = ret;
__usb_packet_complete(ep->dev, p);
usb_packet_complete_one(ep->dev, p);
}
}
......@@ -522,7 +533,8 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state)
p->state = state;
}
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id)
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
bool short_not_ok, bool int_req)
{
assert(!usb_packet_is_inflight(p));
assert(p->iov.iov != NULL);
......@@ -531,6 +543,8 @@ void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id)
p->ep = ep;
p->result = 0;
p->parameter = 0;
p->short_not_ok = short_not_ok;
p->int_req = int_req;
qemu_iovec_reset(&p->iov);
usb_packet_set_state(p, USB_PACKET_SETUP);
}
......
......@@ -362,7 +362,6 @@ struct EHCIPacket {
USBPacket packet;
QEMUSGList sgl;
int pid;
uint32_t tbytes;
enum async_state async;
int usb_status;
};
......@@ -382,7 +381,7 @@ struct EHCIQueue {
uint32_t qhaddr; /* address QH read from */
uint32_t qtdaddr; /* address QTD read from */
USBDevice *dev;
QTAILQ_HEAD(, EHCIPacket) packets;
QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
};
typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
......@@ -444,6 +443,7 @@ struct EHCIState {
uint64_t last_run_ns;
uint32_t async_stepdown;
bool int_req_by_async;
};
#define SET_LAST_RUN_CLOCK(s) \
......@@ -488,6 +488,7 @@ static const char *ehci_mmio_names[] = {
static int ehci_state_executing(EHCIQueue *q);
static int ehci_state_writeback(EHCIQueue *q);
static int ehci_fill_queue(EHCIPacket *p);
static const char *nr2str(const char **n, size_t len, uint32_t nr)
{
......@@ -1245,7 +1246,7 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
s->usbcmd = val; /* Set usbcmd for ehci_update_halt() */
ehci_update_halt(s);
s->async_stepdown = 0;
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
qemu_bh_schedule(s->async_bh);
}
break;
......@@ -1456,8 +1457,15 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
}
p = container_of(packet, EHCIPacket, packet);
trace_usb_ehci_packet_action(p->queue, p, "wakeup");
assert(p->async == EHCI_ASYNC_INFLIGHT);
if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
trace_usb_ehci_packet_action(p->queue, p, "remove");
ehci_free_packet(p);
return;
}
trace_usb_ehci_packet_action(p->queue, p, "wakeup");
p->async = EHCI_ASYNC_FINISHED;
p->usb_status = packet->result;
......@@ -1505,15 +1513,20 @@ static void ehci_execute_complete(EHCIQueue *q)
}
} else {
// TODO check 4.12 for splits
uint32_t tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
if (p->tbytes && p->pid == USB_TOKEN_IN) {
p->tbytes -= p->usb_status;
if (tbytes && p->pid == USB_TOKEN_IN) {
tbytes -= p->usb_status;
if (tbytes) {
/* 4.15.1.2 must raise int on a short input packet */
ehci_raise_irq(q->ehci, USBSTS_INT);
}
} else {
p->tbytes = 0;
tbytes = 0;
}
DPRINTF("updating tbytes to %d\n", p->tbytes);
set_field(&q->qh.token, p->tbytes, QTD_TOKEN_TBYTES);
DPRINTF("updating tbytes to %d\n", tbytes);
set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);
}
ehci_finish_transfer(q, p->usb_status);
usb_packet_unmap(&p->packet, &p->sgl);
......@@ -1525,6 +1538,9 @@ static void ehci_execute_complete(EHCIQueue *q)
if (q->qh.token & QTD_TOKEN_IOC) {
ehci_raise_irq(q->ehci, USBSTS_INT);
if (q->async) {
q->ehci->int_req_by_async = true;
}
}
}
......@@ -1535,6 +1551,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
USBEndpoint *ep;
int ret;
int endp;
bool spd;
assert(p->async == EHCI_ASYNC_NONE ||
p->async == EHCI_ASYNC_INITIALIZED);
......@@ -1544,8 +1561,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
return USB_RET_PROCERR;
}
p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
if (p->tbytes > BUFF_SIZE) {
if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) {
ehci_trace_guest_bug(p->queue->ehci,
"guest requested more bytes than allowed");
return USB_RET_PROCERR;
......@@ -1575,17 +1591,18 @@ static int ehci_execute(EHCIPacket *p, const char *action)
return USB_RET_PROCERR;
}
usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr, spd,
(p->qtd.token & QTD_TOKEN_IOC) != 0);
usb_packet_map(&p->packet, &p->sgl);
p->async = EHCI_ASYNC_INITIALIZED;
}
trace_usb_ehci_packet_action(p->queue, p, action);
ret = usb_handle_packet(p->queue->dev, &p->packet);
DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
"(total %d) endp %x ret %d\n",
DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd endp %x ret %d\n",
q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
q->packet.iov.size, q->tbytes, endp, ret);
q->packet.iov.size, endp, ret);
if (ret > BUFF_SIZE) {
fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
......@@ -1646,10 +1663,10 @@ static int ehci_process_itd(EHCIState *ehci,
dev = ehci_find_device(ehci, devaddr);
ep = usb_ep_get(dev, pid, endp);
if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
usb_packet_setup(&ehci->ipacket, pid, ep, addr);
usb_packet_setup(&ehci->ipacket, pid, ep, addr, false,
(itd->transact[i] & ITD_XACT_IOC) != 0);
usb_packet_map(&ehci->ipacket, &ehci->isgl);
ret = usb_handle_packet(dev, &ehci->ipacket);
assert(ret != USB_RET_ASYNC);
usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
} else {
DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
......@@ -1988,7 +2005,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
{
EHCIqtd qtd;
EHCIPacket *p;
int again = 0;
int again = 1;
get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
sizeof(EHCIqtd) >> 2);
......@@ -2016,7 +2033,6 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
p = NULL;
}
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
again = 1;
} else if (p != NULL) {
switch (p->async) {
case EHCI_ASYNC_NONE:
......@@ -2025,6 +2041,9 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
break;
case EHCI_ASYNC_INFLIGHT:
/* Check if the guest has added new tds to the queue */
again = (ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)) ==
USB_RET_PROCERR) ? -1 : 1;
/* Unfinished async handled packet, go horizontal */
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
break;
......@@ -2036,13 +2055,11 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
ehci_set_state(q->ehci, q->async, EST_EXECUTING);
break;
}
again = 1;
} else {
p = ehci_alloc_packet(q);
p->qtdaddr = q->qtdaddr;
p->qtd = qtd;
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
again = 1;
}
return again;
......@@ -2065,18 +2082,23 @@ static int ehci_state_horizqh(EHCIQueue *q)
static int ehci_fill_queue(EHCIPacket *p)
{
USBEndpoint *ep = p->packet.ep;
EHCIQueue *q = p->queue;
EHCIqtd qtd = p->qtd;
uint32_t qtdaddr;
uint32_t qtdaddr, start_addr = p->qtdaddr;
for (;;) {
if (NLPTR_TBIT(qtd.altnext) == 0) {
break;
}
if (NLPTR_TBIT(qtd.next) != 0) {
break;
}
qtdaddr = qtd.next;
/*
* 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;
}
get_dwords(q->ehci, NLPTR_GET(qtdaddr),
(uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd);
......@@ -2093,6 +2115,9 @@ static int ehci_fill_queue(EHCIPacket *p)
assert(p->usb_status == USB_RET_ASYNC);
p->async = EHCI_ASYNC_INFLIGHT;
}
if (p->usb_status != USB_RET_PROCERR) {
usb_device_flush_ep_queue(ep->dev, ep);
}
return p->usb_status;
}
......@@ -2198,19 +2223,6 @@ static int ehci_state_writeback(EHCIQueue *q)
* bit is clear.
*/
if (q->qh.token & QTD_TOKEN_HALT) {
/*
* We should not do any further processing on a halted queue!
* This is esp. important for bulk endpoints with pipelining enabled
* (redirection to a real USB device), where we must cancel all the
* transfers after this one so that:
* 1) If they've completed already, they are not processed further
* causing more stalls, originating from the same failed transfer
* 2) If still in flight, they are cancelled before the guest does
* a clear stall, otherwise the guest and device can loose sync!
*/
while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
ehci_free_packet(p);
}
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
again = 1;
} else {
......@@ -2502,18 +2514,19 @@ static void ehci_frame_timer(void *opaque)
}
if (need_timer) {
expire_time = t_now + (get_ticks_per_sec()
/* If we've raised int, we speed up the timer, so that we quickly
* notice any new packets queued up in response */
if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) {
expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 2);
ehci->int_req_by_async = false;
} else {
expire_time = t_now + (get_ticks_per_sec()
* (ehci->async_stepdown+1) / FRAME_TIMER_FREQ);
}
qemu_mod_timer(ehci->frame_timer, expire_time);
}
}
static void ehci_async_bh(void *opaque)
{
EHCIState *ehci = opaque;
ehci_advance_async_state(ehci);
}
static const MemoryRegionOps ehci_mmio_caps_ops = {
.read = ehci_caps_read,
.valid.min_access_size = 1,
......@@ -2742,7 +2755,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
}
s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
s->async_bh = qemu_bh_new(ehci_async_bh, s);
s->async_bh = qemu_bh_new(ehci_frame_timer, s);
QTAILQ_INIT(&s->aqueues);
QTAILQ_INIT(&s->pqueues);
usb_packet_init(&s->ipacket);
......
......@@ -627,7 +627,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
dev = usb_find_device(&s->port, ep->faddr[idx]);
uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
usb_packet_setup(&ep->packey[dir].p, pid, uep,
(dev->addr << 16) | (uep->nr << 8) | pid);
(dev->addr << 16) | (uep->nr << 8) | pid, false, true);
usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
......@@ -635,6 +635,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ret = usb_handle_packet(dev, &ep->packey[dir].p);
if (ret == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, uep);
ep->status[dir] = len;
return;
}
......
......@@ -810,12 +810,15 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
if (completion) {
ret = ohci->usb_packet.result;
} else {
bool int_req = relative_frame_number == frame_count &&
OHCI_BM(iso_td.flags, TD_DI) == 0;
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
usb_packet_setup(&ohci->usb_packet, pid, ep, addr);
usb_packet_setup(&ohci->usb_packet, pid, ep, addr, false, int_req);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, ep);
return 1;
}
}
......@@ -1011,13 +1014,15 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
usb_packet_setup(&ohci->usb_packet, pid, ep, addr);
usb_packet_setup(&ohci->usb_packet, pid, ep, addr, !flag_r,
OHCI_BM(td.flags, TD_DI) == 0);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
ret = usb_handle_packet(dev, &ohci->usb_packet);
#ifdef DEBUG_PACKET
DPRINTF("ret=%d\n", ret);
#endif
if (ret == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, ep);
ohci->async_td = addr;
return 1;
}
......
此差异已折叠。
......@@ -322,6 +322,7 @@ typedef struct XHCITransfer {
bool running_retry;
bool cancelled;
bool complete;
bool int_req;
unsigned int iso_pkts;
unsigned int slotid;
unsigned int epid;
......@@ -416,6 +417,8 @@ struct XHCIState {
/* properties */
uint32_t numports_2;
uint32_t numports_3;
uint32_t numintrs;
uint32_t numslots;
uint32_t flags;
/* Operational Registers */
......@@ -815,8 +818,8 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
dma_addr_t erdp;
unsigned int dp_idx;
if (v >= MAXINTRS) {
DPRINTF("intr nr out of range (%d >= %d)\n", v, MAXINTRS);
if (v >= xhci->numintrs) {
DPRINTF("intr nr out of range (%d >= %d)\n", v, xhci->numintrs);
return;
}
intr = &xhci->intr[v];
......@@ -963,6 +966,12 @@ static void xhci_er_reset(XHCIState *xhci, int v)
XHCIInterrupter *intr = &xhci->intr[v];
XHCIEvRingSeg seg;
if (intr->erstsz == 0) {
/* disabled */
intr->er_start = 0;
intr->er_size = 0;
return;
}
/* cache the (sole) event ring segment location */
if (intr->erstsz != 1) {
fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", intr->erstsz);
......@@ -1008,9 +1017,6 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
uint32_t state)
{
uint32_t ctx[5];
if (epctx->state == state) {
return;
}
pci_dma_read(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx));
ctx[0] &= ~EP_STATE_MASK;
......@@ -1039,7 +1045,7 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
int i;
trace_usb_xhci_ep_enable(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
assert(epid >= 1 && epid <= 31);
slot = &xhci->slots[slotid-1];
......@@ -1082,13 +1088,42 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
return CC_SUCCESS;
}
static int xhci_ep_nuke_one_xfer(XHCITransfer *t)
{
int killed = 0;
if (t->running_async) {
usb_cancel_packet(&t->packet);
t->running_async = 0;
t->cancelled = 1;
DPRINTF("xhci: cancelling transfer, waiting for it to complete\n");
killed = 1;
}
if (t->running_retry) {
XHCIEPContext *epctx = t->xhci->slots[t->slotid-1].eps[t->epid-1];
if (epctx) {
epctx->retry = NULL;
qemu_del_timer(epctx->kick_timer);
}
t->running_retry = 0;
}
if (t->trbs) {
g_free(t->trbs);
}
t->trbs = NULL;
t->trb_count = t->trb_alloced = 0;
return killed;
}
static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
unsigned int epid)
{
XHCISlot *slot;
XHCIEPContext *epctx;
int i, xferi, killed = 0;
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
assert(epid >= 1 && epid <= 31);
DPRINTF("xhci_ep_nuke_xfers(%d, %d)\n", slotid, epid);
......@@ -1103,25 +1138,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
xferi = epctx->next_xfer;
for (i = 0; i < TD_QUEUE; i++) {
XHCITransfer *t = &epctx->transfers[xferi];
if (t->running_async) {
usb_cancel_packet(&t->packet);
t->running_async = 0;
t->cancelled = 1;
DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i);
killed++;
}
if (t->running_retry) {
t->running_retry = 0;
epctx->retry = NULL;
qemu_del_timer(epctx->kick_timer);
}
if (t->trbs) {
g_free(t->trbs);
}
t->trbs = NULL;
t->trb_count = t->trb_alloced = 0;
killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi]);
xferi = (xferi + 1) % TD_QUEUE;
}
return killed;
......@@ -1134,7 +1151,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
XHCIEPContext *epctx;
trace_usb_xhci_ep_disable(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
assert(epid >= 1 && epid <= 31);
slot = &xhci->slots[slotid-1];
......@@ -1164,7 +1181,7 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
XHCIEPContext *epctx;
trace_usb_xhci_ep_stop(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
if (epid < 1 || epid > 31) {
fprintf(stderr, "xhci: bad ep %d\n", epid);
......@@ -1198,7 +1215,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
USBDevice *dev;
trace_usb_xhci_ep_reset(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
if (epid < 1 || epid > 31) {
fprintf(stderr, "xhci: bad ep %d\n", epid);
......@@ -1248,7 +1265,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
XHCIEPContext *epctx;
dma_addr_t dequeue;
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
if (epid < 1 || epid > 31) {
fprintf(stderr, "xhci: bad ep %d\n", epid);
......@@ -1281,18 +1298,22 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
return CC_SUCCESS;
}
static int xhci_xfer_map(XHCITransfer *xfer)
static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer)
{
int in_xfer = (xfer->packet.pid == USB_TOKEN_IN);
XHCIState *xhci = xfer->xhci;
int i;
xfer->int_req = false;
pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count);
for (i = 0; i < xfer->trb_count; i++) {
XHCITRB *trb = &xfer->trbs[i];
dma_addr_t addr;
unsigned int chunk = 0;
if (trb->control & TRB_TR_IOC) {
xfer->int_req = true;
}
switch (TRB_TYPE(*trb)) {
case TR_DATA:
if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
......@@ -1317,7 +1338,6 @@ static int xhci_xfer_map(XHCITransfer *xfer)
}
}
usb_packet_map(&xfer->packet, &xfer->sgl);
return 0;
err:
......@@ -1435,8 +1455,10 @@ static int xhci_setup_packet(XHCITransfer *xfer)
ep = usb_ep_get(dev, dir, xfer->epid >> 1);
}
usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr);
xhci_xfer_map(xfer);
xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr, false,
xfer->int_req);
usb_packet_map(&xfer->packet, &xfer->sgl);
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
xfer->packet.pid, dev->addr, ep->nr);
return 0;
......@@ -1641,12 +1663,13 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
{
XHCIEPContext *epctx;
USBEndpoint *ep = NULL;
uint64_t mfindex;
int length;
int i;
trace_usb_xhci_ep_kick(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
assert(epid >= 1 && epid <= 31);
if (!xhci->slots[slotid-1].enabled) {
......@@ -1734,12 +1757,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
if (epid == 1) {
if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
ep = xfer->packet.ep;
} else {
fprintf(stderr, "xhci: error firing CTL transfer\n");
}
} else {
if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
ep = xfer->packet.ep;
} else {
if (!xfer->iso_xfer) {
fprintf(stderr, "xhci: error firing data transfer\n");
......@@ -1756,12 +1781,15 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
break;
}
}
if (ep) {
usb_device_flush_ep_queue(ep->dev, ep);
}
}
static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
{
trace_usb_xhci_slot_enable(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
xhci->slots[slotid-1].enabled = 1;
xhci->slots[slotid-1].uport = NULL;
memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31);
......@@ -1774,7 +1802,7 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
int i;
trace_usb_xhci_slot_disable(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
for (i = 1; i <= 31; i++) {
if (xhci->slots[slotid-1].eps[i-1]) {
......@@ -1826,7 +1854,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
TRBCCode res;
trace_usb_xhci_slot_address(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx));
......@@ -1865,7 +1893,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
return CC_USB_TRANSACTION_ERROR;
}
for (i = 0; i < MAXSLOTS; i++) {
for (i = 0; i < xhci->numslots; i++) {
if (xhci->slots[i].uport == uport) {
fprintf(stderr, "xhci: port %s already assigned to slot %d\n",
uport->path, i+1);
......@@ -1914,7 +1942,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
TRBCCode res;
trace_usb_xhci_slot_configure(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
ictx = xhci_mask64(pictx);
octx = xhci->slots[slotid-1].ctx;
......@@ -2002,7 +2030,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
uint32_t slot_ctx[4];
trace_usb_xhci_slot_evaluate(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
ictx = xhci_mask64(pictx);
octx = xhci->slots[slotid-1].ctx;
......@@ -2065,7 +2093,7 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
int i;
trace_usb_xhci_slot_reset(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(slotid >= 1 && slotid <= xhci->numslots);
octx = xhci->slots[slotid-1].ctx;
......@@ -2091,7 +2119,7 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr
{
unsigned int slotid;
slotid = (trb->control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK;
if (slotid < 1 || slotid > MAXSLOTS) {
if (slotid < 1 || slotid > xhci->numslots) {
fprintf(stderr, "xhci: bad slot id %d\n", slotid);
event->ccode = CC_TRB_ERROR;
return 0;
......@@ -2183,12 +2211,12 @@ static void xhci_process_commands(XHCIState *xhci)
event.ptr = addr;
switch (type) {
case CR_ENABLE_SLOT:
for (i = 0; i < MAXSLOTS; i++) {
for (i = 0; i < xhci->numslots; i++) {
if (!xhci->slots[i].enabled) {
break;
}
}
if (i >= MAXSLOTS) {
if (i >= xhci->numslots) {
fprintf(stderr, "xhci: no device slots available\n");
event.ccode = CC_NO_SLOTS_ERROR;
} else {
......@@ -2335,7 +2363,7 @@ static void xhci_reset(DeviceState *dev)
xhci->config = 0;
xhci->devaddr = 2;
for (i = 0; i < MAXSLOTS; i++) {
for (i = 0; i < xhci->numslots; i++) {
xhci_disable_slot(xhci, i+1);
}
......@@ -2343,7 +2371,7 @@ static void xhci_reset(DeviceState *dev)
xhci_update_port(xhci, xhci->ports + i, 0);
}
for (i = 0; i < MAXINTRS; i++) {
for (i = 0; i < xhci->numintrs; i++) {
xhci->intr[i].iman = 0;
xhci->intr[i].imod = 0;
xhci->intr[i].erstsz = 0;
......@@ -2375,7 +2403,7 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
break;
case 0x04: /* HCSPARAMS 1 */
ret = ((xhci->numports_2+xhci->numports_3)<<24)
| (MAXINTRS<<8) | MAXSLOTS;
| (xhci->numintrs<<8) | xhci->numslots;
break;
case 0x08: /* HCSPARAMS 2 */
ret = 0x0000000f;
......@@ -2402,7 +2430,7 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
ret = 0x02000402; /* USB 2.0 */
break;
case 0x24: /* Supported Protocol:04 */
ret = 0x20425455; /* "USB " */
ret = 0x20425355; /* "USB " */
break;
case 0x28: /* Supported Protocol:08 */
ret = 0x00000001 | (xhci->numports_2<<8);
......@@ -2414,7 +2442,7 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
ret = 0x03000002; /* USB 3.0 */
break;
case 0x34: /* Supported Protocol:04 */
ret = 0x20425455; /* "USB " */
ret = 0x20425355; /* "USB " */
break;
case 0x38: /* Supported Protocol:08 */
ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8);
......@@ -2653,7 +2681,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
trace_usb_xhci_runtime_write(reg, val);
if (reg < 0x20) {
fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg);
fprintf(stderr, "%s: reg 0x%x unimplemented\n", __func__, (int)reg);
return;
}
......@@ -2730,7 +2758,7 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
(uint32_t)val);
}
} else {
if (reg > MAXSLOTS) {
if (reg > xhci->numslots) {
fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg);
} else if (val > 31) {
fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n",
......@@ -2822,6 +2850,10 @@ static void xhci_complete(USBPort *port, USBPacket *packet)
{
XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
xhci_ep_nuke_one_xfer(xfer);
return;
}
xhci_complete_packet(xfer, packet->result);
xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
}
......@@ -2832,7 +2864,7 @@ static void xhci_child_detach(USBPort *uport, USBDevice *child)
XHCIState *xhci = container_of(bus, XHCIState, bus);
int i;
for (i = 0; i < MAXSLOTS; i++) {
for (i = 0; i < xhci->numslots; i++) {
if (xhci->slots[i].uport == uport) {
xhci->slots[i].uport = NULL;
}
......@@ -2852,7 +2884,7 @@ static int xhci_find_slotid(XHCIState *xhci, USBDevice *dev)
XHCISlot *slot;
int slotid;
for (slotid = 1; slotid <= MAXSLOTS; slotid++) {
for (slotid = 1; slotid <= xhci->numslots; slotid++) {
slot = &xhci->slots[slotid-1];
if (slot->devaddr == dev->addr) {
return slotid;
......@@ -2948,6 +2980,19 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
usb_xhci_init(xhci, &dev->qdev);
if (xhci->numintrs > MAXINTRS) {
xhci->numintrs = MAXINTRS;
}
if (xhci->numintrs < 1) {
xhci->numintrs = 1;
}
if (xhci->numslots > MAXSLOTS) {
xhci->numslots = MAXSLOTS;
}
if (xhci->numslots < 1) {
xhci->numslots = 1;
}
xhci->mfwrap_timer = qemu_new_timer_ns(vm_clock, xhci_mfwrap_timer, xhci);
xhci->irq = xhci->pci_dev.irq[0];
......@@ -2984,10 +3029,10 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
assert(ret >= 0);
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
msi_init(&xhci->pci_dev, 0x70, MAXINTRS, true, false);
msi_init(&xhci->pci_dev, 0x70, xhci->numintrs, true, false);
}
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) {
msix_init(&xhci->pci_dev, MAXINTRS,
msix_init(&xhci->pci_dev, xhci->numintrs,
&xhci->mem, 0, OFF_MSIX_TABLE,
&xhci->mem, 0, OFF_MSIX_PBA,
0x90);
......@@ -3002,10 +3047,12 @@ static const VMStateDescription vmstate_xhci = {
};
static Property xhci_properties[] = {
DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
DEFINE_PROP_END_OF_LIST(),
};
......
......@@ -1224,7 +1224,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
usb_ep_set_type(&s->dev, pid, ep, type);
usb_ep_set_ifnum(&s->dev, pid, ep, interface);
if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
(type == USB_ENDPOINT_XFER_BULK)) {
(type == USB_ENDPOINT_XFER_BULK) &&
(pid == USB_TOKEN_OUT)) {
usb_ep_set_pipeline(&s->dev, pid, ep, true);
}
......
......@@ -1270,6 +1270,16 @@ static void usbredir_interface_info(void *priv,
}
}
static void usbredir_set_pipeline(USBRedirDevice *dev, struct USBEndpoint *uep)
{
if (uep->type != USB_ENDPOINT_XFER_BULK) {
return;
}
if (uep->pid == USB_TOKEN_OUT) {
uep->pipeline = true;
}
}
static void usbredir_ep_info(void *priv,
struct usb_redir_ep_info_header *ep_info)
{
......@@ -1311,9 +1321,7 @@ static void usbredir_ep_info(void *priv,
dev->endpoint[i].max_packet_size =
usb_ep->max_packet_size = ep_info->max_packet_size[i];
}
if (ep_info->type[i] == usb_redir_type_bulk) {
usb_ep->pipeline = true;
}
usbredir_set_pipeline(dev, usb_ep);
}
}
......@@ -1574,9 +1582,7 @@ static int usbredir_post_load(void *priv, int version_id)
usb_ep->type = dev->endpoint[i].type;
usb_ep->ifnum = dev->endpoint[i].interface;
usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
if (dev->endpoint[i].type == usb_redir_type_bulk) {
usb_ep->pipeline = true;
}
usbredir_set_pipeline(dev, usb_ep);
}
return 0;
}
......
......@@ -295,7 +295,7 @@ usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%04x"
usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%08x"
usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%08x"
usb_uhci_queue_add(uint32_t token) "token 0x%x"
usb_uhci_queue_del(uint32_t token) "token 0x%x"
usb_uhci_queue_del(uint32_t token, const char *reason) "token 0x%x: %s"
usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x"
usb_uhci_packet_link_async(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x"
usb_uhci_packet_unlink_async(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册