1 From 985807ab66338c6a9cab8d68a2b52b0cff0423ee Mon Sep 17 00:00:00 2001
2 From: Gerd Hoffmann <kraxel@redhat.com>
3 Date: Fri, 17 Aug 2012 11:04:36 +0200
4 Subject: [PATCH] xhci: drop buffering
6 This patch splits the xhci_xfer_data function into three.
7 The xhci_xfer_data function used to do does two things:
9 (1) copy transfer data between guest memory and a temporary buffer.
10 (2) report transfer results to the guest using events.
12 Now we three functions to handle this:
14 (1) xhci_xfer_map creates a scatter list for the transfer and
15 uses that (instead of the temporary buffer) to build a
17 (2) xhci_xfer_unmap undoes the mapping.
18 (3) xhci_xfer_report sends out events.
20 The patch also fixes reporting of transaction errors which must be
21 reported unconditinally, not only in case the guest asks for it
26 Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
27 (cherry picked from commit d5a15814b413869667b2a3215772986885be574a)
29 Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
31 hw/usb/hcd-xhci.c | 185 +++++++++++++++++++++---------------------------------
33 2 files changed, 72 insertions(+), 115 deletions(-)
35 diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
36 index c0a2476..446d692 100644
37 --- a/hw/usb/hcd-xhci.c
38 +++ b/hw/usb/hcd-xhci.c
39 @@ -305,6 +305,7 @@ typedef struct XHCIState XHCIState;
40 typedef struct XHCITransfer {
47 @@ -319,10 +320,6 @@ typedef struct XHCITransfer {
48 unsigned int trb_alloced;
51 - unsigned int data_length;
52 - unsigned int data_alloced;
58 @@ -906,14 +903,9 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
68 t->trb_count = t->trb_alloced = 0;
69 - t->data_length = t->data_alloced = 0;
70 xferi = (xferi + 1) % TD_QUEUE;
73 @@ -1072,24 +1064,13 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
77 -static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
78 - unsigned int length, bool in_xfer, bool out_xfer,
80 +static int xhci_xfer_map(XHCITransfer *xfer)
84 - unsigned int transferred = 0;
85 - unsigned int left = length;
88 - XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
89 + int in_xfer = (xfer->packet.pid == USB_TOKEN_IN);
90 XHCIState *xhci = xfer->xhci;
93 - DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n",
94 - length, in_xfer, out_xfer, report);
96 - assert(!(in_xfer && out_xfer));
98 + pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count);
99 for (i = 0; i < xfer->trb_count; i++) {
100 XHCITRB *trb = &xfer->trbs[i];
102 @@ -1099,54 +1080,70 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
104 if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
105 fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
107 - return transferred;
113 addr = xhci_mask64(trb->parameter);
114 chunk = trb->status & 0x1ffff;
115 + if (trb->control & TRB_TR_IDT) {
116 + if (chunk > 8 || in_xfer) {
117 + fprintf(stderr, "xhci: invalid immediate data TRB\n");
120 + qemu_sglist_add(&xfer->sgl, trb->addr, chunk);
122 + qemu_sglist_add(&xfer->sgl, addr, chunk);
128 + usb_packet_map(&xfer->packet, &xfer->sgl);
132 + qemu_sglist_destroy(&xfer->sgl);
137 +static void xhci_xfer_unmap(XHCITransfer *xfer)
139 + usb_packet_unmap(&xfer->packet, &xfer->sgl);
140 + qemu_sglist_destroy(&xfer->sgl);
143 +static void xhci_xfer_report(XHCITransfer *xfer)
145 + uint32_t edtla = 0;
149 + XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
150 + XHCIState *xhci = xfer->xhci;
153 + left = xfer->packet.result < 0 ? 0 : xfer->packet.result;
155 + for (i = 0; i < xfer->trb_count; i++) {
156 + XHCITRB *trb = &xfer->trbs[i];
157 + unsigned int chunk = 0;
159 + switch (TRB_TYPE(*trb)) {
163 + chunk = trb->status & 0x1ffff;
168 - if (in_xfer || out_xfer) {
169 - if (trb->control & TRB_TR_IDT) {
171 - if (chunk > 8 || in_xfer) {
172 - fprintf(stderr, "xhci: invalid immediate data TRB\n");
174 - return transferred;
176 - idata = le64_to_cpu(trb->parameter);
177 - memcpy(data, &idata, chunk);
179 - DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at "
180 - DMA_ADDR_FMT "\n", in_xfer, chunk, addr);
182 - pci_dma_write(&xhci->pci_dev, addr, data, chunk);
184 - pci_dma_read(&xhci->pci_dev, addr, data, chunk);
187 - unsigned int count = chunk;
193 - for (i = 0; i < count; i++) {
194 - DPRINTF(" %02x", data[i]);
198 + if (xfer->status == CC_SUCCESS) {
205 - transferred += chunk;
209 @@ -1154,8 +1151,9 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
213 - if (report && !reported && (trb->control & TRB_TR_IOC ||
214 - (shortpkt && (trb->control & TRB_TR_ISP)))) {
215 + if (!reported && ((trb->control & TRB_TR_IOC) ||
216 + (shortpkt && (trb->control & TRB_TR_ISP)) ||
217 + (xfer->status != CC_SUCCESS))) {
218 event.slotid = xfer->slotid;
219 event.epid = xfer->epid;
220 event.length = (trb->status & 0x1ffff) - chunk;
221 @@ -1175,9 +1173,11 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
223 xhci_event(xhci, &event);
225 + if (xfer->status != CC_SUCCESS) {
230 - return transferred;
233 static void xhci_stall_ep(XHCITransfer *xfer)
234 @@ -1204,7 +1204,7 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
235 dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
236 ep = usb_ep_get(dev, dir, xfer->epid >> 1);
237 usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr);
238 - usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
239 + xhci_xfer_map(xfer);
240 DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
241 xfer->packet.pid, dev->addr, ep->nr);
243 @@ -1230,12 +1230,13 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
244 xfer->running_async = 0;
245 xfer->running_retry = 0;
247 + xhci_xfer_unmap(xfer);
251 - xfer->status = CC_SUCCESS;
252 - xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1);
253 trace_usb_xhci_xfer_success(xfer, ret);
254 + xfer->status = CC_SUCCESS;
255 + xhci_xfer_report(xfer);
259 @@ -1244,12 +1245,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
262 xfer->status = CC_USB_TRANSACTION_ERROR;
263 - xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
264 + xhci_xfer_report(xfer);
268 xfer->status = CC_STALL_ERROR;
269 - xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
270 + xhci_xfer_report(xfer);
274 @@ -1271,7 +1272,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
276 XHCITRB *trb_setup, *trb_status;
277 uint8_t bmRequestType;
282 @@ -1279,8 +1279,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
283 trb_setup = &xfer->trbs[0];
284 trb_status = &xfer->trbs[xfer->trb_count-1];
286 - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid,
287 - trb_setup->parameter >> 48);
288 + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
290 /* at most one Event Data TRB allowed after STATUS */
291 if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
292 @@ -1309,19 +1308,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
295 bmRequestType = trb_setup->parameter;
296 - wLength = trb_setup->parameter >> 48;
298 - if (xfer->data && xfer->data_alloced < wLength) {
299 - xfer->data_alloced = 0;
300 - g_free(xfer->data);
304 - DPRINTF("xhci: alloc %d bytes data\n", wLength);
305 - xfer->data = g_malloc(wLength+1);
306 - xfer->data_alloced = wLength;
308 - xfer->data_length = wLength;
310 port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
311 dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
312 @@ -1336,9 +1322,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
314 xhci_setup_packet(xfer, dev);
315 xfer->packet.parameter = trb_setup->parameter;
316 - if (!xfer->in_xfer) {
317 - xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
320 ret = usb_handle_packet(dev, &xfer->packet);
322 @@ -1359,16 +1342,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
324 xfer->in_xfer = epctx->type>>2;
326 - if (xfer->data && xfer->data_alloced < xfer->data_length) {
327 - xfer->data_alloced = 0;
328 - g_free(xfer->data);
331 - if (!xfer->data && xfer->data_length) {
332 - DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length);
333 - xfer->data = g_malloc(xfer->data_length);
334 - xfer->data_alloced = xfer->data_length;
336 if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
339 @@ -1402,9 +1375,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
343 - if (!xfer->in_xfer) {
344 - xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0);
346 ret = usb_handle_packet(dev, &xfer->packet);
348 xhci_complete_packet(xfer, ret);
349 @@ -1416,20 +1386,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
351 static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
354 - unsigned int length = 0;
357 - for (i = 0; i < xfer->trb_count; i++) {
358 - trb = &xfer->trbs[i];
359 - if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) {
360 - length += trb->status & 0x1ffff;
364 - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length);
366 - xfer->data_length = length;
367 + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
368 return xhci_submit(xhci, xfer, epctx);
371 diff --git a/trace-events b/trace-events
372 index 10bc04e..c83d65e 100644
375 @@ -326,7 +326,7 @@ usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
376 usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
377 usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
378 usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
379 -usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t length) "%p: slotid %d, epid %d, length %d"
380 +usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d"
381 usb_xhci_xfer_async(void *xfer) "%p"
382 usb_xhci_xfer_nak(void *xfer) "%p"
383 usb_xhci_xfer_retry(void *xfer) "%p"