xhci: let class driver set urb->start_frame and try to shedule isoc at it.
use the urb->start_frame as a possible starting frame for isoc transfers,
urb->start_frame should be 1-2047 for LS and FS devices (frames)
urb->start_frame should be 1-16383 for HS or faster (microframes)
if microframes then preferrably divisible by eight as xhci can only
schedule on even frames anyway.
note that not accepring zero as urb->start_frame is a known bug
that should be fixed later by adding a urb flag instead indicating
if urb->start_frame should be used or not
xhci driver will (at least in most cases)
overwrite the urb->start_frame with the actual frame used.
This test probably beaks CFC feature as will, check it later.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 99b4ff4..62f46cb 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3670,22 +3670,23 @@
ret = -EINVAL;
}
+ if (ret) {
+ xhci_warn(xhci, "Frame ID %d (reg %d, index %d) beyond range (%d, %d)\n",
+ start_frame, current_frame_id, index,
+ start_frame_id, end_frame_id);
+ }
if (index == 0) {
- if (ret == -EINVAL || start_frame == start_frame_id) {
+ if (ret == -EINVAL || start_frame == start_frame_id)
start_frame = start_frame_id + 1;
- if (urb->dev->speed == USB_SPEED_LOW ||
- urb->dev->speed == USB_SPEED_FULL)
- urb->start_frame = start_frame;
- else
- urb->start_frame = start_frame << 3;
- ret = 0;
- }
+ if (urb->dev->speed == USB_SPEED_LOW ||
+ urb->dev->speed == USB_SPEED_FULL)
+ urb->start_frame = start_frame;
+ else
+ urb->start_frame = start_frame << 3;
+ ret = 0;
}
if (ret) {
- xhci_warn(xhci, "Frame ID %d (reg %d, index %d) beyond range (%d, %d)\n",
- start_frame, current_frame_id, index,
- start_frame_id, end_frame_id);
xhci_warn(xhci, "Ignore frame ID field, use SIA bit instead\n");
return ret;
}
@@ -3710,7 +3711,7 @@
int i, j;
bool more_trbs_coming;
struct xhci_virt_ep *xep;
- int frame_id;
+ int frame_id = -EINVAL;
xep = &xhci->devs[slot_id]->eps[ep_index];
ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
@@ -3759,12 +3760,12 @@
/* use SIA as default, if frame id is used overwrite it */
sia_frame_id = TRB_SIA;
- if (!(urb->transfer_flags & URB_ISO_ASAP) &&
- HCC_CFC(xhci->hcc_params)) {
+ if (!(urb->transfer_flags & URB_ISO_ASAP)) {
frame_id = xhci_get_isoc_frame_id(xhci, urb, i);
if (frame_id >= 0)
sia_frame_id = TRB_FRAME_ID(frame_id);
}
+
/*
* Set isoc specific data for the first TRB in a TD.
* Prevent HW from getting the TRBs by keeping the cycle state
@@ -3947,6 +3948,14 @@
urb->interval /= 8;
}
+ /*
+ * if urb->start_frame is set by a class driver, note that we consider
+ * start_frame 0 invalid here
+ */
+
+ if ((urb->start_frame) && !(urb->transfer_flags & URB_ISO_ASAP))
+ goto skip_start_over;
+
/* Calculate the start frame and put it in urb->start_frame. */
if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {
if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
@@ -3955,7 +3964,6 @@
goto skip_start_over;
}
}
-
start_frame = readl(&xhci->run_regs->microframe_index);
start_frame &= 0x3fff;
/*