@@ -140,6 +140,7 @@
#define NB_PORTS 6 // Number of downstream ports
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
#define MAX_QH 100 // Max allowable queue heads in a chain
+#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
/* Internal periodic / asynchronous schedule state machine states
*/
@@ -2461,6 +2462,19 @@ static void ehci_frame_timer(void *opaque)
}
for (i = 0; i < frames; i++) {
+ /*
+ * If we're running behind schedule, we should not catch up
+ * too fast, as that will make some guests unhappy:
+ * 1) We must process a minimum of MIN_FR_PER_TICK frames,
+ * otherwise we will never catch up
+ * 2) Process frames until the guest has requested an irq (IOC)
+ */
+ if (i >= MIN_FR_PER_TICK) {
+ ehci_commit_irq(ehci);
+ if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) {
+ break;
+ }
+ }
ehci_update_frindex(ehci, 1);
ehci_advance_periodic_state(ehci);
ehci->last_run_ns += FRAME_TIMER_NS;
The Linux ehci isoc scheduling code fills the entire schedule ahead of time minus 80 frames. If we make a large jump in where we are in the schedule, ie 40 frames, then the scheduler all of a sudden will only have 40 frames left to work in, causing it to fail packet submissions with error -27 (-EFBIG). Changes in v2: -Don't hardcode a maximum number of frames to process in one tick, instead: -Process a minimum number of frames to ensure we do eventually catch up -Stop (after the minimum number) when the guest has requested an irq Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- hw/usb/hcd-ehci.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)