[PATCH v2] usb: xhci: fix lack of short packet event trb handling

For bulk IN transfer, the codes will set ISP flag to request event TRB being generated by xHC for case of short packet. So in buffer-cross-64K-boundary case (which we will divide payload and enqueuqe more than 1 transfer TRB), if the first TRB ends up with a short packet condition it will trigger an short packet code transfer event per that flag and cause more than 1 event TRB gegerated for this transfer.
However, current codes will only handle the first transfer event TRB then mark current transfer completed, which causing next transfer failure due to event TRB mis-match.
Such issue has been observed on some Layerscape platforms (LS1028A, LS1088A, etc) with USB ethernet device
This patch adds a loop to make sure the event TRB for last transfer TRB has been handled in time.
Signed-off-by: Ran Wang ran.wang_1@nxp.com --- Change in v2: - Re-write commit message to describe context more clearly. - Add prefix 'le64_to_cpu' for 'event->trans_event.buffer'.
drivers/usb/host/xhci-ring.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 13065d7..e0ccf01 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -580,10 +580,13 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, int ret; u32 trb_fields[4]; u64 val_64 = virt_to_phys(buffer); + void *last_transfer_trb_addr; + int available_length;
debug("dev=%p, pipe=%lx, buffer=%p, length=%d\n", udev, pipe, buffer, length);
+ available_length = length; ep_index = usb_pipe_ep_index(pipe); virt_dev = ctrl->devs[slot_id];
@@ -697,7 +700,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, trb_fields[2] = length_field; trb_fields[3] = field | TRB_TYPE(TRB_NORMAL);
- queue_trb(ctrl, ring, (num_trbs > 1), trb_fields); + last_transfer_trb_addr = queue_trb(ctrl, ring, (num_trbs > 1), trb_fields);
--num_trbs;
@@ -710,6 +713,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
giveback_first_trb(udev, ep_index, start_cycle, start_trb);
+again: event = xhci_wait_for_event(ctrl, TRB_TRANSFER); if (!event) { debug("XHCI bulk transfer timed out, aborting...\n"); @@ -718,12 +722,19 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, udev->act_len = 0; return -ETIMEDOUT; } - field = le32_to_cpu(event->trans_event.flags);
+ if ((void *)le64_to_cpu(event->trans_event.buffer) != last_transfer_trb_addr) { + available_length -= + (int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len)); + xhci_acknowledge_event(ctrl); + goto again; + } + + field = le32_to_cpu(event->trans_event.flags); BUG_ON(TRB_TO_SLOT_ID(field) != slot_id); BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
- record_transfer_result(udev, event, length); + record_transfer_result(udev, event, available_length); xhci_acknowledge_event(ctrl); xhci_inval_cache((uintptr_t)buffer, length);

Hi Ran,
On Mon, Nov 16, 2020 at 2:38 PM Ran Wang ran.wang_1@nxp.com wrote:
For bulk IN transfer, the codes will set ISP flag to request event TRB being generated by xHC for case of short packet. So in
for the case of
buffer-cross-64K-boundary case (which we will divide payload and enqueuqe more than 1 transfer TRB), if the first TRB ends up with a short packet condition it will trigger an short packet code transfer event per that flag and cause more than 1 event TRB gegerated for this transfer.
typo: generated
However, current codes will only handle the first transfer event TRB then mark current transfer completed, which causing next transfer
which causing => causing
failure due to event TRB mis-match.
Such issue has been observed on some Layerscape platforms (LS1028A, LS1088A, etc) with USB ethernet device
nits: missing ending period
This patch adds a loop to make sure the event TRB for last transfer TRB has been handled in time.
nits: please remove one space before `handled`
Signed-off-by: Ran Wang ran.wang_1@nxp.com
Change in v2:
- Re-write commit message to describe context more clearly.
- Add prefix 'le64_to_cpu' for 'event->trans_event.buffer'.
drivers/usb/host/xhci-ring.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
Other than above, Reviewed-by: Bin Meng bmeng.cn@gmail.com
Regards, Bin
participants (2)
-
Bin Meng
-
Ran Wang