From 640d89650839c858964265a885e62572de060685 Mon Sep 17 00:00:00 2001 From: Xiaoguang Wu Date: Tue, 17 Jul 2018 20:48:45 +0800 Subject: [PATCH] DM USB: change TRB ring processing logic for ISOC transfer Current ring buffer processing logic assumes every transaction will be submited to physical device before next transaction coming. So it use two states 0 (free) and 1 (used) to represent the state of every data block in the ring buffer. With the help of the two state, the ring buffer could accept and process data normally. But this logic is not proper for ISOC transfer, which generally submits many transactions even none of them arrive the physical device. So this patch uses three values to represent the state of data block in the ring buffer: USB_XFER_BLK_FREE: this block could be filled with new data; USB_XFER_BLK_HANDLING: this block is submited to physical device but response from device is still not received; USB_XFER_BLK_HANDLED: this block has been processed by physical device. The new logic will do different things for each state, which will make the ISOC transfer work successfully. Change-Id: I5559cae24c739633289742d64dd51751797b81a7 Tracked-On: Signed-off-by: Xiaoguang Wu Reviewed-by: Liang Yang Acked-by: Yu Wang --- devicemodel/hw/pci/xhci.c | 36 +++++++++++---------------- devicemodel/hw/platform/usb_mouse.c | 6 ++--- devicemodel/hw/platform/usb_pmapper.c | 22 +++++++++++----- devicemodel/hw/usb_core.c | 2 +- devicemodel/include/usb_core.h | 22 ++++++++++------ 5 files changed, 49 insertions(+), 39 deletions(-) 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 {