[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 12/22] usb: Move short-not-ok handling to the core
From: |
Hans de Goede |
Subject: |
[Qemu-devel] [PATCH 12/22] usb: Move short-not-ok handling to the core |
Date: |
Mon, 15 Oct 2012 12:38:21 +0200 |
After a short-not-ok packet ending short, we should not advance the queue.
Move enforcing this to the core, rather then handling it in the hcd code.
This may result in the queue now actually containing multiple input packets
(which would not happen before), and this requires special handling in
combination with pipelining, so disable pipleining for input endpoints
(for now).
Signed-off-by: Hans de Goede <address@hidden>
---
hw/usb.h | 4 +++-
hw/usb/core.c | 6 ++++--
hw/usb/hcd-ehci.c | 9 ++++-----
hw/usb/hcd-musb.c | 2 +-
hw/usb/hcd-ohci.c | 4 ++--
hw/usb/hcd-uhci.c | 7 ++++---
hw/usb/hcd-xhci.c | 2 +-
hw/usb/host-linux.c | 3 ++-
hw/usb/redirect.c | 18 ++++++++++++------
9 files changed, 33 insertions(+), 22 deletions(-)
diff --git a/hw/usb.h b/hw/usb.h
index ead03c9..1fcf79c 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -351,6 +351,7 @@ struct USBPacket {
USBEndpoint *ep;
QEMUIOVector iov;
uint64_t parameter; /* control transfers */
+ bool short_not_ok;
int result; /* transfer length or USB_RET_* status code */
/* Internal use by the USB layer. */
USBPacketState state;
@@ -360,7 +361,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);
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);
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 5a97a0e..f4a5ad2 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -423,7 +423,7 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
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);
@@ -532,7 +532,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)
{
assert(!usb_packet_is_inflight(p));
assert(p->iov.iov != NULL);
@@ -541,6 +542,7 @@ 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;
qemu_iovec_reset(&p->iov);
usb_packet_set_state(p, USB_PACKET_SETUP);
}
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index e6f7642..4dfe0f3 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1550,6 +1550,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);
@@ -1589,7 +1590,8 @@ 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);
usb_packet_map(&p->packet, &p->sgl);
p->async = EHCI_ASYNC_INITIALIZED;
}
@@ -1659,7 +1661,7 @@ 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);
usb_packet_map(&ehci->ipacket, &ehci->isgl);
ret = usb_handle_packet(dev, &ehci->ipacket);
assert(ret != USB_RET_ASYNC);
@@ -2083,9 +2085,6 @@ static int ehci_fill_queue(EHCIPacket *p)
uint32_t qtdaddr, start_addr = p->qtdaddr;
for (;;) {
- if (NLPTR_TBIT(qtd.altnext) == 0) {
- break;
- }
if (NLPTR_TBIT(qtd.next) != 0) {
break;
}
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
index 4896d38..f65fa3c 100644
--- a/hw/usb/hcd-musb.c
+++ b/hw/usb/hcd-musb.c
@@ -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);
usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index a3207f0..8741d0f 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -812,7 +812,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct
ohci_ed *ed,
} else {
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);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret == USB_RET_ASYNC) {
@@ -1012,7 +1012,7 @@ 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);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
ret = usb_handle_packet(dev, &ohci->usb_packet);
#ifdef DEBUG_PACKET
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 00dc9d5..953897b 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -808,6 +808,7 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr,
UHCI_TD *td,
UHCIAsync *async;
int len = 0, max_len;
uint8_t pid;
+ bool spd;
USBDevice *dev;
USBEndpoint *ep;
@@ -852,13 +853,14 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr,
UHCI_TD *td,
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
+ spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
if (ep_ret) {
*ep_ret = ep;
}
- usb_packet_setup(&async->packet, pid, ep, addr);
+ usb_packet_setup(&async->packet, pid, ep, addr, spd);
qemu_sglist_add(&async->sgl, td->buffer, max_len);
usb_packet_map(&async->packet, &async->sgl);
@@ -985,8 +987,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td,
struct USBEndpoint *ep)
UHCI_TD ptd;
int ret;
- ptd.ctrl = td->ctrl;
- while (is_valid(plink) && !(ptd.ctrl & TD_CTRL_SPD)) {
+ while (is_valid(plink)) {
pci_dma_read(&s->dev, plink & ~0xf, &ptd, sizeof(ptd));
le32_to_cpus(&ptd.link);
le32_to_cpus(&ptd.ctrl);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 5648cc7..f7b37cd 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1455,7 +1455,7 @@ 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);
+ usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr, false);
xhci_xfer_map(xfer);
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
xfer->packet.pid, dev->addr, ep->nr);
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 44f1a64..3a258b4 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -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);
}
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 022ba42..84b9705 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1293,6 +1293,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)
{
@@ -1334,9 +1344,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);
}
}
@@ -1597,9 +1605,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;
}
--
1.7.12.1
- [Qemu-devel] [PATCH 07/22] ehci: Detect going in circles when filling the queue, (continued)
- [Qemu-devel] [PATCH 07/22] ehci: Detect going in circles when filling the queue, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 08/22] xhci: Add a xhci_ep_nuke_one_xfer helper function, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 05/22] ehci: Improve latency of interrupt delivery and async schedule scanning, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 10/22] usb: Add USB_RET_ADD_TO_QUEUE packet result code, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 09/22] usb: Rename __usb_packet_complete to usb_packet_complete_one, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 13/22] usb: Add an int_req flag to USBPacket, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 16/22] usb-redir: When a packet contains data on a stall, ignore the stall, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 17/22] usb-redir: Add support for 32 bits bulk packet length, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 12/22] usb: Move short-not-ok handling to the core,
Hans de Goede <=
- [Qemu-devel] [PATCH 11/22] usb: Move clearing of queue on halt to the core, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 15/22] combined-packet: Add a workaround for Linux usbfs + live migration, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 14/22] usb: Add packet combining functions, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 22/22] usb-redir: Allow redirecting super speed devices to high speed controllers, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 20/22] usb-redir: Use reject rather the disconnect on bad ep info, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 18/22] usb-redir: Add support for input pipelining, Hans de Goede, 2012/10/15
- [Qemu-devel] [PATCH 21/22] usb-redir: Allow to attach USB 2.0 devices to 1.1 host controller, Hans de Goede, 2012/10/15