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 <xiaoguang.wu@intel.com>
Reviewed-by: Liang Yang <liang3.yang@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Xiaoguang Wu
2018-07-17 20:48:45 +08:00
committed by lijinxia
parent d24213db2d
commit 640d896508
5 changed files with 49 additions and 39 deletions

View File

@@ -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;
}
}