Initial commit with version 1.2.0-24
[packages/centos6/qemu.git] / 0152-xhci-drop-buffering.patch
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
5
6 This patch splits the xhci_xfer_data function into three.
7 The xhci_xfer_data function used to do does two things:
8
9   (1) copy transfer data between guest memory and a temporary buffer.
10   (2) report transfer results to the guest using events.
11
12 Now we three functions to handle this:
13
14   (1) xhci_xfer_map creates a scatter list for the transfer and
15       uses that (instead of the temporary buffer) to build a
16       USBPacket.
17   (2) xhci_xfer_unmap undoes the mapping.
18   (3) xhci_xfer_report sends out events.
19
20 The patch also fixes reporting of transaction errors which must be
21 reported unconditinally, not only in case the guest asks for it
22 using the ISP flag.
23
24 [ v2: fix warning ]
25
26 Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
27 (cherry picked from commit d5a15814b413869667b2a3215772986885be574a)
28
29 Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
30 ---
31  hw/usb/hcd-xhci.c | 185 +++++++++++++++++++++---------------------------------
32  trace-events      |   2 +-
33  2 files changed, 72 insertions(+), 115 deletions(-)
34
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 {
41      XHCIState *xhci;
42      USBPacket packet;
43 +    QEMUSGList sgl;
44      bool running_async;
45      bool running_retry;
46      bool cancelled;
47 @@ -319,10 +320,6 @@ typedef struct XHCITransfer {
48      unsigned int trb_alloced;
49      XHCITRB *trbs;
50  
51 -    unsigned int data_length;
52 -    unsigned int data_alloced;
53 -    uint8_t *data;
54 -
55      TRBCCode status;
56  
57      unsigned int pkts;
58 @@ -906,14 +903,9 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
59          if (t->trbs) {
60              g_free(t->trbs);
61          }
62 -        if (t->data) {
63 -            g_free(t->data);
64 -        }
65  
66          t->trbs = NULL;
67 -        t->data = NULL;
68          t->trb_count = t->trb_alloced = 0;
69 -        t->data_length = t->data_alloced = 0;
70          xferi = (xferi + 1) % TD_QUEUE;
71      }
72      return killed;
73 @@ -1072,24 +1064,13 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
74      return CC_SUCCESS;
75  }
76  
77 -static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
78 -                          unsigned int length, bool in_xfer, bool out_xfer,
79 -                          bool report)
80 +static int xhci_xfer_map(XHCITransfer *xfer)
81  {
82 -    int i;
83 -    uint32_t edtla = 0;
84 -    unsigned int transferred = 0;
85 -    unsigned int left = length;
86 -    bool reported = 0;
87 -    bool shortpkt = 0;
88 -    XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
89 +    int in_xfer = (xfer->packet.pid == USB_TOKEN_IN);
90      XHCIState *xhci = xfer->xhci;
91 +    int i;
92  
93 -    DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n",
94 -            length, in_xfer, out_xfer, report);
95 -
96 -    assert(!(in_xfer && out_xfer));
97 -
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];
101          dma_addr_t addr;
102 @@ -1099,54 +1080,70 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
103          case TR_DATA:
104              if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
105                  fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
106 -                xhci_die(xhci);
107 -                return transferred;
108 +                goto err;
109              }
110              /* fallthrough */
111          case TR_NORMAL:
112          case TR_ISOCH:
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");
118 +                    goto err;
119 +                }
120 +                qemu_sglist_add(&xfer->sgl, trb->addr, chunk);
121 +            } else {
122 +                qemu_sglist_add(&xfer->sgl, addr, chunk);
123 +            }
124 +            break;
125 +        }
126 +    }
127 +
128 +    usb_packet_map(&xfer->packet, &xfer->sgl);
129 +    return 0;
130 +
131 +err:
132 +    qemu_sglist_destroy(&xfer->sgl);
133 +    xhci_die(xhci);
134 +    return -1;
135 +}
136 +
137 +static void xhci_xfer_unmap(XHCITransfer *xfer)
138 +{
139 +    usb_packet_unmap(&xfer->packet, &xfer->sgl);
140 +    qemu_sglist_destroy(&xfer->sgl);
141 +}
142 +
143 +static void xhci_xfer_report(XHCITransfer *xfer)
144 +{
145 +    uint32_t edtla = 0;
146 +    unsigned int left;
147 +    bool reported = 0;
148 +    bool shortpkt = 0;
149 +    XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
150 +    XHCIState *xhci = xfer->xhci;
151 +    int i;
152 +
153 +    left = xfer->packet.result < 0 ? 0 : xfer->packet.result;
154 +
155 +    for (i = 0; i < xfer->trb_count; i++) {
156 +        XHCITRB *trb = &xfer->trbs[i];
157 +        unsigned int chunk = 0;
158 +
159 +        switch (TRB_TYPE(*trb)) {
160 +        case TR_DATA:
161 +        case TR_NORMAL:
162 +        case TR_ISOCH:
163 +            chunk = trb->status & 0x1ffff;
164              if (chunk > left) {
165                  chunk = left;
166 -                shortpkt = 1;
167 -            }
168 -            if (in_xfer || out_xfer) {
169 -                if (trb->control & TRB_TR_IDT) {
170 -                    uint64_t idata;
171 -                    if (chunk > 8 || in_xfer) {
172 -                        fprintf(stderr, "xhci: invalid immediate data TRB\n");
173 -                        xhci_die(xhci);
174 -                        return transferred;
175 -                    }
176 -                    idata = le64_to_cpu(trb->parameter);
177 -                    memcpy(data, &idata, chunk);
178 -                } else {
179 -                    DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at "
180 -                            DMA_ADDR_FMT "\n", in_xfer, chunk, addr);
181 -                    if (in_xfer) {
182 -                        pci_dma_write(&xhci->pci_dev, addr, data, chunk);
183 -                    } else {
184 -                        pci_dma_read(&xhci->pci_dev, addr, data, chunk);
185 -                    }
186 -#ifdef DEBUG_DATA
187 -                    unsigned int count = chunk;
188 -                    int i;
189 -                    if (count > 16) {
190 -                        count = 16;
191 -                    }
192 -                    DPRINTF(" ::");
193 -                    for (i = 0; i < count; i++) {
194 -                        DPRINTF(" %02x", data[i]);
195 -                    }
196 -                    DPRINTF("\n");
197 -#endif
198 +                if (xfer->status == CC_SUCCESS) {
199 +                    shortpkt = 1;
200                  }
201              }
202              left -= chunk;
203 -            data += chunk;
204              edtla += chunk;
205 -            transferred += chunk;
206              break;
207          case TR_STATUS:
208              reported = 0;
209 @@ -1154,8 +1151,9 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
210              break;
211          }
212  
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,
222              }
223              xhci_event(xhci, &event);
224              reported = 1;
225 +            if (xfer->status != CC_SUCCESS) {
226 +                return;
227 +            }
228          }
229      }
230 -    return transferred;
231  }
232  
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);
242      return 0;
243 @@ -1230,12 +1230,13 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
244          xfer->running_async = 0;
245          xfer->running_retry = 0;
246          xfer->complete = 1;
247 +        xhci_xfer_unmap(xfer);
248      }
249  
250      if (ret >= 0) {
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);
256          return 0;
257      }
258  
259 @@ -1244,12 +1245,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
260      switch (ret) {
261      case USB_RET_NODEV:
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);
265          xhci_stall_ep(xfer);
266          break;
267      case USB_RET_STALL:
268          xfer->status = CC_STALL_ERROR;
269 -        xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
270 +        xhci_xfer_report(xfer);
271          xhci_stall_ep(xfer);
272          break;
273      default:
274 @@ -1271,7 +1272,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
275  {
276      XHCITRB *trb_setup, *trb_status;
277      uint8_t bmRequestType;
278 -    uint16_t wLength;
279      XHCIPort *port;
280      USBDevice *dev;
281      int ret;
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];
285  
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);
289  
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)
293      }
294  
295      bmRequestType = trb_setup->parameter;
296 -    wLength = trb_setup->parameter >> 48;
297 -
298 -    if (xfer->data && xfer->data_alloced < wLength) {
299 -        xfer->data_alloced = 0;
300 -        g_free(xfer->data);
301 -        xfer->data = NULL;
302 -    }
303 -    if (!xfer->data) {
304 -        DPRINTF("xhci: alloc %d bytes data\n", wLength);
305 -        xfer->data = g_malloc(wLength+1);
306 -        xfer->data_alloced = wLength;
307 -    }
308 -    xfer->data_length = wLength;
309  
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)
313  
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);
318 -    }
319  
320      ret = usb_handle_packet(dev, &xfer->packet);
321  
322 @@ -1359,16 +1342,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
323  
324      xfer->in_xfer = epctx->type>>2;
325  
326 -    if (xfer->data && xfer->data_alloced < xfer->data_length) {
327 -        xfer->data_alloced = 0;
328 -        g_free(xfer->data);
329 -        xfer->data = NULL;
330 -    }
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;
335 -    }
336      if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
337          xfer->pkts = 1;
338      } else {
339 @@ -1402,9 +1375,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
340          return -1;
341      }
342  
343 -    if (!xfer->in_xfer) {
344 -        xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0);
345 -    }
346      ret = usb_handle_packet(dev, &xfer->packet);
347  
348      xhci_complete_packet(xfer, ret);
349 @@ -1416,20 +1386,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
350  
351  static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
352  {
353 -    int i;
354 -    unsigned int length = 0;
355 -    XHCITRB *trb;
356 -
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;
361 -        }
362 -    }
363 -
364 -    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length);
365 -
366 -    xfer->data_length = length;
367 +    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
368      return xhci_submit(xhci, xfer, epctx);
369  }
370  
371 diff --git a/trace-events b/trace-events
372 index 10bc04e..c83d65e 100644
373 --- a/trace-events
374 +++ b/trace-events
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"
384 -- 
385 1.7.12.1
386