diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c index 9df331b53..0099166df 100644 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -2161,8 +2161,6 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, uint32_t epid, int *do_intr) { - struct pci_xhci_dev_emu *dev; - struct pci_xhci_dev_ep *devep; struct xhci_dev_ctx *dev_ctx; struct xhci_endp_ctx *ep_ctx; struct xhci_trb *trb; @@ -2172,8 +2170,6 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, uint32_t i; int err = XHCI_TRB_ERROR_SUCCESS; - dev = XHCI_SLOTDEV_PTR(xdev, slot); - devep = &dev->eps[epid]; dev_ctx = pci_xhci_get_dev_ctx(xdev, slot); assert(dev_ctx != NULL); @@ -2219,22 +2215,18 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, trbflags, err, trb->dwTrb3 & XHCI_TRB_3_IOC_BIT ? 1 : 0); - if (!xfer->data[i].processed) { + if (xfer->data[i].processed < USB_XFER_BLK_HANDLED) { xfer->head = (int)i; break; } + xfer->data[i].processed = USB_XFER_BLK_FREE; xfer->ndata--; xfer->head = (xfer->head + 1) % USB_MAX_XFER_BLOCKS; edtla += xfer->data[i].bdone; trb->dwTrb3 = (trb->dwTrb3 & ~0x1) | (xfer->data[i].ccs); - pci_xhci_update_ep_ring(xdev, dev, devep, ep_ctx, - xfer->data[i].streamid, - xfer->data[i].trbnext, - xfer->data[i].ccs); - /* Only interrupt if IOC or short packet */ if (!(trb->dwTrb3 & XHCI_TRB_3_IOC_BIT) && !((err == XHCI_TRB_ERROR_SHORT_PKT) && @@ -2415,7 +2407,7 @@ retry: err = XHCI_TRB_ERROR_STALL; goto errout; } - xfer_block->processed = 1; + xfer_block->processed = USB_XFER_BLK_FREE; break; case XHCI_TRB_TYPE_SETUP_STAGE: @@ -2446,7 +2438,7 @@ retry: err = XHCI_TRB_ERROR_STALL; goto errout; } - xfer_block->processed = 1; + xfer_block->processed = USB_XFER_BLK_HANDLED; break; case XHCI_TRB_TYPE_NORMAL: @@ -2480,7 +2472,7 @@ retry: err = XHCI_TRB_ERROR_STALL; goto errout; } - xfer_block->processed = 1; + xfer_block->processed = USB_XFER_BLK_HANDLED; break; case XHCI_TRB_TYPE_EVENT_DATA: @@ -2491,7 +2483,7 @@ retry: goto errout; } if ((epid > 1) && (trbflags & XHCI_TRB_3_IOC_BIT)) - xfer_block->processed = 1; + xfer_block->processed = USB_XFER_BLK_HANDLED; break; default: @@ -2509,18 +2501,20 @@ retry: if (xfer_block) { xfer_block->trbnext = addr; xfer_block->streamid = streamid; - } - - if (!setup_trb && !(trbflags & XHCI_TRB_3_CHAIN_BIT) && - XHCI_TRB_3_TYPE_GET(trbflags) != XHCI_TRB_TYPE_LINK) { - break; + /* FIXME: + * should add some code to process the scenario in + * which endpoint stop command is comming in the + * middle of many data transfers. + */ + pci_xhci_update_ep_ring(xdev, dev, devep, ep_ctx, + xfer_block->streamid, + xfer_block->trbnext, xfer_block->ccs); } /* handle current batch that requires interrupt on complete */ if (trbflags & XHCI_TRB_3_IOC_BIT) { UPRINTF(LDBG, "trb IOC bit set\r\n"); - if (epid == 1) - do_retry = 1; + do_retry = 1; break; } } diff --git a/devicemodel/hw/platform/usb_mouse.c b/devicemodel/hw/platform/usb_mouse.c index 8de488f6e..4a52a695e 100644 --- a/devicemodel/hw/platform/usb_mouse.c +++ b/devicemodel/hw/platform/usb_mouse.c @@ -337,7 +337,7 @@ umouse_request(void *scarg, struct usb_data_xfer *xfer) udata = data->buf; } - xfer->data[idx].processed = 1; + xfer->data[idx].processed = USB_XFER_BLK_HANDLED; idx = (idx + 1) % USB_MAX_XFER_BLOCKS; } @@ -718,7 +718,7 @@ umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir, if (data->buf != NULL && data->blen != 0) break; - data->processed = 1; + data->processed = USB_XFER_BLK_HANDLED; data = NULL; idx = (idx + 1) % USB_MAX_XFER_BLOCKS; } @@ -758,7 +758,7 @@ umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir, if (len > 0) { dev->newdata = 0; - data->processed = 1; + data->processed = USB_XFER_BLK_HANDLED; data->bdone += 6; memcpy(udata, &dev->um_report, 6); data->blen = len - 6; diff --git a/devicemodel/hw/platform/usb_pmapper.c b/devicemodel/hw/platform/usb_pmapper.c index 153903448..d5d6e8d23 100644 --- a/devicemodel/hw/platform/usb_pmapper.c +++ b/devicemodel/hw/platform/usb_pmapper.c @@ -125,7 +125,7 @@ usb_dev_comp_req(struct libusb_transfer *libusb_xfer) } } - /* post process the usb transfer data */ + /* handle the blocks belong to this request */ buf_idx = 0; idx = req->blk_start; for (i = 0; i < req->blk_count; i++) { @@ -152,11 +152,13 @@ usb_dev_comp_req(struct libusb_transfer *libusb_xfer) buf_idx += done; block->bdone = done; block->blen -= done; + block->processed = USB_XFER_BLK_HANDLED; idx = (idx + 1) % USB_MAX_XFER_BLOCKS; } if (short_data) xfer->status = USB_ERR_SHORT_XFER; + out: /* notify the USB core this transfer is over */ if (g_ctx.notify_cb) @@ -233,9 +235,9 @@ usb_dev_prepare_xfer(struct usb_data_xfer *xfer, int *count, int *size) for (i = 0; i < xfer->ndata; i++) { block = &xfer->data[idx]; - if (block->processed) { + if (block->processed == USB_XFER_BLK_HANDLED || + block->processed == USB_XFER_BLK_HANDLING) { idx = (idx + 1) % USB_MAX_XFER_BLOCKS; - c++; continue; } if (block->buf && block->blen > 0) { @@ -245,12 +247,20 @@ usb_dev_prepare_xfer(struct usb_data_xfer *xfer, int *count, int *size) } c++; s += block->blen; - + } else if (!block->buf || !block->blen) { + /* there are two cases: + * 1. LINK trb is in the middle of trbs. + * 2. LINK trb is a single trb. + */ + c++; + block->processed = USB_XFER_BLK_HANDLED; + idx = (idx + 1) % USB_MAX_XFER_BLOCKS; + continue; } else if (found) { UPRINTF(LWRN, "find a NULL data. %d total %d\n", i, xfer->ndata); } - block->processed = 1; + block->processed = USB_XFER_BLK_HANDLING; idx = (idx + 1) % USB_MAX_XFER_BLOCKS; } @@ -558,7 +568,7 @@ usb_dev_prepare_ctrl_xfer(struct usb_data_xfer *xfer) if (blk->blen > 0 && !ret) ret = blk; - blk->processed = 1; + blk->processed = USB_XFER_BLK_HANDLED; idx = (idx + 1) % USB_MAX_XFER_BLOCKS; } return ret; diff --git a/devicemodel/hw/usb_core.c b/devicemodel/hw/usb_core.c index 53396f7e4..4c3ea3f56 100644 --- a/devicemodel/hw/usb_core.c +++ b/devicemodel/hw/usb_core.c @@ -114,7 +114,7 @@ usb_data_xfer_append(struct usb_data_xfer *xfer, void *buf, int blen, xb->blen = blen; xb->hci_data = hci_data; xb->ccs = ccs; - xb->processed = 0; + xb->processed = USB_XFER_BLK_FREE; xb->bdone = 0; xfer->ndata++; xfer->tail = (xfer->tail + 1) % USB_MAX_XFER_BLOCKS; diff --git a/devicemodel/include/usb_core.h b/devicemodel/include/usb_core.h index 64ca72458..3a9648a4f 100644 --- a/devicemodel/include/usb_core.h +++ b/devicemodel/include/usb_core.h @@ -78,6 +78,12 @@ enum usb_dev_type { USB_DEV_PORT_MAPPER }; +enum usb_xfer_blk_stat { + USB_XFER_BLK_FREE = 0, + USB_XFER_BLK_HANDLING, + USB_XFER_BLK_HANDLED +}; + struct usb_hci; struct usb_device_request; struct usb_data_xfer; @@ -133,14 +139,14 @@ struct usb_hci { * of the buffer, i.e. len(buf) - len(consumed). */ struct usb_data_xfer_block { - void *buf; /* IN or OUT pointer */ - int blen; /* in:len(buf), out:len(remaining) */ - int bdone; /* bytes transferred */ - uint32_t processed; /* device processed this + errcode */ - void *hci_data; /* HCI private reference */ - int ccs; - uint32_t streamid; - uint64_t trbnext; /* next TRB guest address */ + void *buf; /* IN or OUT pointer */ + int blen; /* in:len(buf), out:len(remaining) */ + int bdone; /* bytes transferred */ + enum usb_xfer_blk_stat processed; /* processed status */ + void *hci_data; /* HCI private reference */ + int ccs; + uint32_t streamid; + uint64_t trbnext; /* next TRB guest address */ }; struct usb_data_xfer {